====== Springframework Java Config ======
* Spring 3.1 부터 본격적으로 도입됨.
* [[springframework:bean|SpringFramework Bean]]
===== 컨텍스트 클래스 =====
* [[http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/AnnotationConfigApplicationContext.html|AnnotationConfigApplicationContext]]
===== 메소드 인자를 통한 주입 받기 =====
* 한 @Configuration 클래스안에서 FactoryBean으로 생성한 Bean과 그것을 주입 받는 빈이 있을 때, 메소드 직접 호출을 통한 주입이 애매하다. 빈을 생성하는 메소드를 직접 호출하면 FactoryBean 객체가 리턴되기 때문이다.
* 이 때, @Bean 메소드의 인자로 FactoryBean 이 생성한 객체를 주입 받으면 된다.
* **@Bean이 붙은 메소드는 기본적으로 @Autowired가 붙은 메소드 처럼 동작한다.** - 토비의 스프링 3.1 Vol 2. 135 페이지
* ''@Qualifier''를 파라미터에 추가해도 된다.
* 한 메소드에서 여러개를 파라미터로 주입 받아도 된다.
* 꼭, 현재 Configuration 클래스가 아닌 다른 곳에서 생성된 Bean도 주입 받을 수 있다.
@Bean
public Printer printer() {
return new Printer();
}
@Bean
public Hello hello(Printer printer) { // 위에 선언된 printer Bean이 주입됨.
...
hello.setPrinter(printer);
}
===== @Primary =====
* [[http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/context/annotation/Primary.html|@Primary]]
===== 주의할 점 =====
==== Java Config 클래스는 무조건 @Configuration 애노테이션을 붙인다 ====
Java Config용 클래스에 ''@Configuration''을 붙이지 않으면 ''@Bean'' 애노테이션된 메소드에 의한 객체 생성시 **싱글턴이 보장되지 않는다**.
또한 동일 설정 클래스에서 생성한 다른 Bean의 ''@Autowired'' 주입도 안 된다.
==== Spring의 특정 인터페이스를 구현했을 경우 처리 ====
Bean에 주입할 객체를 ''@Bean''으로 생성하지 않고 바로 new로 생성하여 주입하면 Spring의 InitializingBean과 같은 인터페이스를 구현한 것이 정상적으로 호출되지 않아 문제가 될 수 있다.
예)
// WebMVC의 코드 중 일부
// 아래 코드에서 openEntityManagerInViewIterceptor는 BeanFactoryAware 인터페이스를 구현하고 있지만
// 해당 기능이 제대로 작동하지 않게 된다.
OpenEntityManagerInViewInterceptor openEntityManagerInView = new OpenEntityManagerInViewInterceptor();
openEntityManagerInView.setEntityManagerFactory(entityManagerFactory);
// ApplicationContext를 주입받아서 OEMIV 객체에 직접 주있해줬음.
// 단, 항상 entityManagerFactory를 먼저 주입하고 다은에 applicationContext 주입할 것.
// 안그러면 EMF가 여러개일 때 Autowiring 오류가 발생함.
// 가장 좋은 것은 OEMIV를 직접 빈(''@Bean'')으로 생성하는 것.
==== @DependsOn ====
* Bean들간의 의존성 지정. ''@Component'', ''@Bean''과 함께 지정.
* [[http://www.baeldung.com/spring-depends-on|Controlling Bean Creation Order with @DependsOn | Baeldung]]
==== Java Config간의 상호 의존 ====
''XxxJavaConfig'' 클래스와 ''YyyJavaConfig''가 서로가 생성하는 객체를 주입받으려고 하면 문제가 된다.
현재 확인된 바로는 무한 루프를 도는 듯한 상황이 연출되었다.
이런 상황은 만들지 말 것.
==== 하나의 JavaConfig 안에서 Field를 통한 Properties 주입과 @Bean Properties 의 상호 의존 ====
* 하나의 JavaConfig안에서 Field에 ''@Value''로 주입하는 값이, 동일 설정 파일의 ''@Bean''을 통해 생성된 ''Properties'' 객체의 값일 때 **Circular Dependency**가 발생할 수도 있다.
@Configuration
public class SomePropsConfig {
@Value("#{myProperties['myprops.someValue']}")
private int someValue;
public Properties myProperties() {
return new Properties() .....
}
}
* 이 상황은 항상 발생하지는 않았고, 설정 파일이 여러개일 때 발생했다.
* 가설
* 설정파일이 여러개일 때 ''SomePropsConfig'' 객체를 가진 설정파일보다 다른 설정파일이 먼저 로딩됨.
* 해당 다른 설정파일이 ''SomePropsConfig'' 객체를 가진 설정파일에 있는 또 다른 제3의 Bean에 의존함.
* ''SomePropsConfig'' 객체를 생성하면서 먼저 Field Injection을 시도하고 그 뒤에 ''@Bean''을 생성하는데, Field가 동일 설정 파일의 ''@Bean myProperties'' 객체에 의존하는 상황.
==== BeanFactoryPostProcessor ====
* [[http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanFactoryPostProcessor.html|BeanFactoryPostProcessor]] 구현체는 ''static''으로 등록해야 한다. 대표적으로 [[http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.html|PropertySourcesPlaceholderConfigurer]]가 그렇다.
==== Bean의 List/Map 주입받기 ====
* [[https://www.baeldung.com/spring-autowire-generics|Spring Autowiring of Generic Types | Baeldung]]
private List dataSources; // 모든 DataSource Bean 목록 주입
private Map dataSourcesByBeanName; // beanName 을 key로 하여 모든 DataSource bean 주입