====== Annotation-based configuration ======
===== 개요 =====
===== 설명 =====
Spring Framework는 Spring의 종속성 삽입을 위해 annotation을 사용할 수 있다. 본질적으호 ''@Autowired'' annotation은 자동 엮음과 같은 기능을 제공하지만, 좀 더 세밀한 제어와 넓은 사용성을 제공한다. Spring Framework는 ''@Resource'', ''@PostConstruct'', ''@PreDestroy'' 등의 JSR-250 annotation도 지원한다. 물론 최소 Java 5(Tiger)를 사용하는 경우 사용 가능하다. 이들 annotation을 사용하기 위해서는 Spring container에 특정 ''BeanPostProcessors''를 등록해야만 한다. 항상 그렇듯이, 이들 ''BeanPostProcessors''가 개별적인 bean 정의로 등록될 수도 있지만, '''context''' namespace를 사용하여 등록할 수도 있다.
(위 '''' tag를 사용하면, ''AutowiredAnnotationBeanPostProcessor'', ''CommonAnnotationBeanPostProcessor'', ''PersistenceAnnotationBeanPostProcessor'', ''RequiredAnnotationBeanPostProcessor''를 등록해준다.)
==== @Required ====
''@Required'' annotation은 bean property setter 메소드에 적용된다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
이 annotation은 단순히 bean property가 설정 시 반드시 설정되어야만 한다는 것을 나타낸다. 즉, bean 정의에 명시적으로 property 값을 선언하거나 자동 엮임을 통해서 설정되어야만 한다는 것을 의미한다. 만약 annotation이 적용된 bean property에 대한 설정이 이루어지지 않는 경우, container는 exception을 던진다.
==== @Autowired ====
''@Autowired'' annotation은 "전통적인" setter 메소드에 적용된다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
뿐만 아니라, 임의의 이름과 다수의 argument를 가진 메소드에도 적용될 수 있다.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
또한, ''@Autowired'' annotation은 생성자 및 field에도 적용될 수 있다.
public class MovieRecommender {
@Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
또한, array 타입의 field나 메소드에 적용함으로써, ''ApplicationContext''에 존재하는 특정 Type의 모든 bean을 field나 메소드에 제공하는 것도 가능한다.
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
Typed collections에도 같은 방식이 적용된다.
public class MovieRecommender {
private Set movieCatalogs;
@Autowired
public void setMovieCatalogs(Set movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
심지어 typed Map 역시 key 타입이 ''String''인 한 자동엮임이 가능하다. Map은 기대한 타입의 모든 bean을 value로 갖게되고, key는 해당하는 bean의 이름이 된다.
public class MovieRecommender {
private Map movieCatalogs;
@Autowired
public void setMovieCatalogs(Map movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
기본적으로, 자동엮임은 대상이 되는 bean이 없을 경우 실패한다. 기본적으로 annotation이 적용된 메소드, 생성자, field는 필수로 간주한다. 아래와 같이 설정하여 기본 행동 방식을 변경할 수 있다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required=false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
''@Autowired'' annotatio은 잘 알려진 "분석가능한 종속성(resolvable dependencies)"에도 사용될 수 있다 : ''BeanFactory'' interface, ''ApplicationContext'' interface, ''ResourceLoader'' interface, ''ApplicationEventPublisher'' interface, ''MessageSource'' interface(그리고 이들을 상속한 ''ConfigurableApplicationContext'' 또는 ''ResourcePatternResolver'' interface)는 특별한 설정 없이 자동적으로 해결(resolve)된다.
==== Qualifier를 사용한 annotation 기반의 자동 엮음(Fine-tuning annotation-based autowiring with qualifiers) ====
Type을 이용한 자동엮기는 대상이 다수가 발생할 수 있기 때문에, 선택 시 추가적인 제어가 필요하다. 한 방법으로 Spring의 ''@Qualifier'' annotation을 사용할 수 있다. 특정 argument를 qualifier와 관련시킴으로써, 타입을 찾을 대상을 좁히고, 각 argument에 해당하는 대상 bean을 선택할 수 있다.
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
''@Qualifier'' annotation은 생성자의 argument 및 메소드의 parameter 각각에 적용할 수 있다.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
일치하는 bean 정의는 아래 예제에서 찾을 수 있다. Qualifier "main" 값을 가진 bean이 같은 값의 ''@Qualifier'' annotation이 있는 생성자 argument로 엮인다.
대체 수단으로, bean 이름을 qualifier로 간주된다. 즉, qualifier element 대신 bean id가 "main"이라면 동일하게 동작한다. 어쨌든, 이름으로 bean을 찾는게 더 좋지만, ''@Autowired''는 기본적으로 type을 기반으로 동작하고 qualifier는 선택적이다. 즉, 타입으로 bean 대상을 줄인 후에 qualifier 또는 bean name으로 대상을 좁힌다. Qualifier 값은 의미적으로 유일한 bean id를 나타내지는 않는다. 좋은 qualifier 값은 "main", "EMEA", "persistent" 등과 같이 bean id가 아닌 특정 컴포넌트의 특징을 표현하는 것이다.
Qualifier는 typed collection에도 적용된다.
==== @Resource ====
Spring은 field나 bean property setter 메소드에 적용된 JSR-250 ''@Resource'' annotation을 사용하여 종속성 삽입을 지원한다.
''@Resource''는 '''name''' attribute를 가지고, Spring은 그 값을 삽입할 bean 이름으로 인식한다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
만약 name이 명식적으로 설정되어 있지 않으면, field나 setter 메소드의 이름으로 부터 name 값을 유추해낸다. Field의 경우, field 명과 같다. Setter 메소드의 경우, bean property 이름과 같다. 아래 예제에서는 "movieFinder" bean이 삽입된다.
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
''@Autowired''와 비슷하게, ''@Resource''도 대안으로 bean type으로 대상을 찾는다. 뿐만 아니라 잘 알려진 "resolvable dependencies"로 해결한다. 둘 다 명시적으로 name을 설정하지 않은 경우 적용된다.
다음 예에서 ''customerPreferenceDao'' field를 위해서 "customerPreferenceDao" 이름을 가진 bean을 먼저 찾는다. 그 다음으로 ''CustomerPreferenceDao'' Type의 bean을 찾는다. "context" field는 얄려진 해결가능한 종속성 type인 ''ApplicationContext''이 기반하여 삽입된다.
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
==== @PostConstrutor와 @PreDestroy ====
''CommonAnnotationBeanPostProcessor''는 ''@Resource'' annotation 뿐 아니라 JST-250 //lifecycle// annotation 역시 인식한다.
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
===== 참고자료 =====
* [[https://docs.spring.io/spring-framework/docs/5.3.20/reference/html/core.html#context-introduction|Spring Framework - Reference Document / 1.15 Annotation-based container configuration]]