Components
원문 : Chapter 2. Components
애노테이션을 사용하여 자바 구조를 계층화 하는 자바 설정은, 개발자들이 자바만을 사용하여 빈을 생성하고 설정할 수 있도록 한다. 간단하게, 개발자는 자바 코드를 사용하여 빈을 만들고 설정하며, 컨테이너가 그것들을 사용하도록 지시한다. 계속 진행하기 전에, Spring의 이상은 설정파일이 어떤 형태든(자바든 XML이든) 상관없이 우지 된다는 것을 유념하라.
JavaConfig에서 사용할 수 있는 가장 중요한 애노테이션들을 살펴보자:
2.1. @Configuration
@Configuration 애노테이션은 설정 클래스를 지칭한다:
@Configuration
public class WebConfiguration {
// bean definitions follow
}
@Configuration은 클레스에 적용하는 애노테이션이고 설정할 bean들에 기본으로 적용할 것들을 나타낸다.
@Configuration(defaultAutowire = Autowire.BY_TYPE, defaultLazy = Lazy.FALSE)
public class DataSourceConfiguration
extends ConfigurationSupport {
}
<beans/> 태그와 동일하게 생각하면 된다. @Configuration 애노테이션을 달고 있는 클레스는 유틸리티 메소드를 제공하는 ConfigurationSupport 를 확장함을 나타낸다.
2.2. @Bean
이름이 암시하듯이, @Bean 애노테이션은 bean 정의(<bean/> 태그)를 나타낸다. 간단한 예제로 살펴보자.
@Bean (scope = DefaultScopes.SESSION)
public ExampleBean exampleBean() {
return new ExampleBean();
}
위의 코드는 Spring 컨테이너에게 method의 이름(bean name)을 사용하여 bean을 생성하도록 하고, 값(실제 bean 객체)을 반환한다. bean은 session 스콥이다. 즉, exampleBean() 메소드는 HTTP session 마다 새로운 객체를 생성해 줄 것이다.
순수 자바 코드를 사용하기 때문에:
- static method를 사용하면 factory-mathod를 사용할 필요가 없다.
@Bean
public ExampleBean exampleBean() {
return ExampleFactory.createBean();
}
또한
- 복잡한 객체 생성시 필요한 FactoryBean/MethodInvokingFactoryBean도 필요없다.
@Bean(aliases = { "anniversaries" })
public List<Date> birthdays() {
List<Date> dates = new ArrayList<Date>();
Calendar calendar = Calendar.getInstance();
calendar.set(1977, 05, 28);
dates.add(calendar.getTime());
dates.add(computeMotherInLawBirthday());
return dates;
}
@Bean은 메소드에 붙일 수 있는 애노테이션이고 bean 객체를 생성하고 설정할 때 사용할 자바 코드를 나타낸다. 이 애노테이션은 XML 빈 설정에서 사용할 수 있는 autowiring, lazy-init, dependecy-check, depends-on과 scope과 같은 대부분의 설정을 지원한다. 또한, 라이프사이클 메소드와 XXXAware 인터페이스도 전부 지원한다.
public class AwareBean implements BeanFactoryAware {
private BeanFactory factory;
// BeanFactoryAware setter
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
public void close(){
// do clean-up
}
}
@Bean(destroyMethodName = "close", lazy = Lazy.TRUE)
public AwareBean createBeanFactoryAwareBean() {
return new AwareBean();
}
destroyMethodNanme 외에도, @Bean 애노테이션은 initMethodName을 제공한다. though its usage is discourage as one already has
control over the object creation and thus can call the initializing
method if needed.
2.3. @ExternalBean
@ExternalBean은 단순한 마크업 애노테이션으로 '부모 애플리케이션 컨텍스트'에 정의 되어 있는 '외부의' 빈을 인젝션 할 때 사용한다. 예제를 살펴보자:
@Configuration
public abstract class ExternalBeanConfiguration {
@Bean
public TestBean james() {
TestBean james = new TestBean();
// inject dependency from ann()
james.setSpouse(ann());
return james;
}
// Will be taken from the parent context
@ExternalBean
public abstract TestBean ann();
}
JavaConfig가 @ExternalBean을 만나게 되면, 소유하고 있는 메소드를 오버라이드하여 언제든 메소드를 호출할 수 있도록 한다. '부모 애플리케이션 컨텍스트'는 메소드 이름에 해당하는 bean을 찾아 준다(bean naming과 관련된 챕터에서 보다 자세한 내용을 참조). 이런 방법을, 설정 파일은 순수 자바로 남을 수 있고 익숙하게 리팩터링 할 수 있다.
@ExternalBean이 일반 메소드에도 역시 작동함을 기억하라. 위의 예제는 추상 메소드를 사용하여 실행되지도 않을 쓰레기 코드를 작성하는 것을 방지했다.
@Configuration
public class ExternalBeanOnNormalMethod {
@ExternalBean
public TestBean ann(){
System.out.println("this code will not execute as the method " +
"will be overriden with a bean look up at runtime");
}
}
2.4. @ScopedProxy
Spring은 scoped 프록시(자세한 내용은 링크 참조)를 사용하여 scoped 종속성의 사용을 편리하게 했다. 그런 프록시를 생성하는 가장 쉬운 방법은, XML 설정을 사용할 때는 <aop:scope-proxy/> 태그를 사용하는 것이였다. JavaConfig는 그 대안으로 @ScopedProxy 애노테이션을 제공하여 동일한 semantic과 설정 옵션을 사용할 수 있다.
XML을 사용한 레퍼런스의 문서에 있는 예제를 JavaConfig를 사용하여 다음과 같이 작성할 수 있다.
// a HTTP Session-scoped bean exposed as a proxy
@Bean(scope = DefaultScopes.SESSION)
@ScopedProxy
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// a reference to the proxied 'userPreferences' bean
service.seUserPreferences(userPreferences());
return service;
}