BeanDefinition 라는 메타데이터가 있다:BeanFactory 인터페이스: IoC 컨테이너의 한 종류로서 오브젝트를 관리해주는 기능을 제공해준다.ApplicationContext 인터페이스: BeanFactory에서 기능이 더 추가된 것이다.Spring 컨테이너가 생성될 때 각 bean의 configuration에 대한 validation을 한다. 그러나 bean properties는 실제로 bean이 생성되기 전까지는 설정되지 않는다. singleton-scoped이고 pre-instantiated인 bean은 컨테이너가 생성될 때 생성된다.
Dependency Injection은 오브젝트와 dependency를 decouple 하기 때문에 코드가 더 간결해진다. 두 가지의 DI 방식이 있다.
B b = new B();
A a = new A();
a.setB(b);
B b = new B();
A a = new A(b);
Dependency resolution 과정은 다음과 같다.
ApplicationContext 가 모든 bean에 대한 정보가 있는 configuration metadata 를 바탕으로 초기화된다. Configuration metadata는 XML, Java 코드, 혹은 annotation을 통해 정의할 수 있다.Circular dependencies
BeanCurrentlyInCreationException 을 발생시킨다.@Lazy 를 통해서도 가능한가..?Spring이 ApplicationContext의 데이터를 바탕으로 bean에 대한 collaborator를 정해주도록 할 수 있다.
autowiring mode는 네 가지가 있다.
ref 값 설정을 통해 해야한다.@Primary 혹은 @Qualifier 를 통해 해결할 수 있다.autowiring의 한계점도 있다.
property와 constructor-arg의 명시적인 dependency 설정이 autowiring을 override한다.Strings나 Classes와 같은 primitive는 autowire할 수 없다.기본적으로는 byType으로 autowiring 한다. 근데 해당 type의 오브젝트가 여러 개일 때는 byName과 같이 @Qualifier를 사용할 수 있다.
@Autowired
@Qualifier("item1")
public void setItem(Item item) {
...
}
Item 클래스의 bean이 여러 개일 때 bean id가 item1인 오브젝트를 찾아서 주입한다.
@Autowired를 필드에 붙일 수도 있다. 그러면 default constructor 호출할 때 binding을 한다. default constructor 호출이 안 되는 상황이라면 사용할 수 없다.
public class CandyStore implements Store {
@Autowired
@Qualifier("item1")
private Item item;
public CandyStore() {
System.out.println("constructor");
}
...
}
@Autowired를 Constructor에 쓸 때는 Qualifier를 parameter에 붙여야한다.
public class CandyStore implements Store {
private Item item;
@Autowired
public CandyStore(@Qualifier("item1") Item item) {
System.out.println("constructor");
}
...
}
@Autowired(required=false) 로 설정하면 해당 bean이 없어도 null로 들어가고 exception이 발생하지 않는다.
Bean definition은 실제 인스턴스를 생성하는 recipe라고 이해하면 된다. 하나의 recipe로 여러 오브젝트 인스턴스를 만들 수도 있다.
6개의 bean scope가 지원된다. 다음 중 request, session, application, websocket은 web-aware Spring인 ApplicationContext에서만 사용 가능하다.

getBean() 메소드를 호출함으로써 bean을 얻을 수 있다.
@RequestScope)@SessionScope)Session마다 하나의 bean definition을 적용한다.@ApplicationScope)Servletcontext 마다 하나의 bean definition을 적용한다.WebSocket마다 하나의 bean definition을 적용한다.@Component, @Service, @Repository, @Controller 등을 사용한다.@Autowired 혹은 constructor injection을 통해 이루어진다.Component에 대해 디폴트 값을 넣어주려면 @Value를 사용한다.
@Component
public class CandyStore implements Store {
@Value("10")
private int stock;
}
혹은 @Value("${[property.name](http://property.name/):defaultValue}") 와 같은 방법으로 정의할 수도 있다.
@Autowired, @Inject, @Value, @Resource annotation 들의 동작은 Spring의 BeanPostProcessor 에 의해 처리된다. 따라서 BeanPostProcessor나 BeanFactoryPostProcessor 타입에는 이런 annotation을 사용할 수 없다. 대신 XML이나 @Bean 메소드를 통해서 직접 wire up 해야한다.
Basic Concepts
@Configuration, @Bean, @Import, @DependsOn annotation 을 사용한다.@Configuration annotation을 추가한다. 그 다음에 각 bean을 생성할 method에 @Bean annotation을 추가한다.@Bean 메소드에서 처리한다.@Bean@Component나 @Configuration 로 annotate된 클래스에서 사용한다.@Configuration@Bean 로 annotate 된 메소드를 통해 bean을 선언한다.Injecting Inter-bean Dependencies
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
beanOne이 constructor injection을 통해서 beanTwo에 대한 reference를 받게 된다.
이런 inter-bean dependencies는 @Component 클래스에서는 Constructor based DI를 통해 사용할 수 없다. setter based DI로는 되는 것 같다.
XML configuration
<beans xmlns=...>
<context:component-scan base-package="my.example.entity" />
<bean id="item" class="my.example.entity.Item" />
</beans>
Java configuration
@ComponentScan("my.example.entity")
@Configuration
public class AppConfig {
// @Bean 메소드의 이름은 bean id가 되기 때문에 getItem 이 아니라 명사형인 item 으로 한다.
@Bean
public Item item() {
return new Item();
}
}
보완: bean lifecycle - PostConstruct, PreDestroy annotation에 대한 정리도 하자.
References