본문 바로가기
Homo Faber/Idioms

Spring에서 annotation 태그 사용하기 (1) - @Autowired

by javauser 2008. 2. 20.
annotation과 같이 BeanPostProcessor를 사용하는 RequiredAnnotationBeanProcessor는 Spring의 IoC 컨테이너를 확장하는 보편적인 방법이다. 예를 들어, Spring 2.0은 @Required annotation을 사용해서 강제적으로 엮여야(wired) 되는 속성에 대해서 소개하고 있다. Spring 2.5 에서도 동일하게 Spring의 의존성 주입(dependency injection)을 위해서 동일한 일반적인 방법으로 사용할 수 있다. 근본적으로 @Autowired annotation은 autowiring과 동일한 기능을 제공하지만 세밀하게 조절이 가능하고 더 넓게 적용이 가능하다. Spring 2.5는 또한 @Resource, @PostConstruct, @PreDestroy와 같은 JSR-250 annotation을 지원한다. 물론, 이러한 옵션들은 최소한 Java 5 (Tiger)를 사용하고 소스 차원 annotation 접근을 할 수 있어야만 가능하다. 이러한 annotation 사용은 또한 특정 BeanPostProcessor가 Spring 컨테이너 내에 등록되어야 함을 의미한다. Spring에서 항상 그렇듯이 이는 개별 bean 정의가 등록됨을 의미하지만, XML 기반 Spring 설정에 다음과 같은 태그를 포함함으로써 등록이 가능하다.
('context' 네임스페이스가 포함)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-2.5.xsd">
   <context:annotation-config/>
</beans>
(위의 등록된 post-processor는 AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationPostProcessor 뿐만 아니라 RequiredAnnotationBeanPostProcessor를 포함한다.)

@Autowired
@Autowired annotation은 아래 예제처럼 전형적인 setter 메소드에 적용될 수 있다.
public class SimpleMovieLister {
   private MovieFinder movieFinder;
   @Autowired
   public void setMovieFinder(MovieFinder movieFinder) {
      this.moveFinder = movieFinder;
   }
   // ...
}

이 annotation은 또한 임의의 이름이나 인자를 여러개 있는 메소드에서도 적용될 수 있다.
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은 심지어 생성자나 필드에도 적용될 수 있다.
public class MovieRecommender {
   @Autowired
   private MovieCatalog movieCatalog;
   private CustomerPreferenceDao customerPreferenceDao;
   @Autowired
   public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
      this.customerPreferenceDao = customerPreferenceDao;
   }
   // ...
}

또한 해당 타입이 배열인 필드나 메소드에 annotation을 추가하여 ApplicationContext로부터 특정 타입의 모든 빈들을 제공하는 것이 가능하다.
public class MovieRecommender {
   @Autowired
   private MovieCatalog[] movieCatalogs;
   // ...
}

만일 자바 5를 사용하고 있다면, 타입이 지정된 collection에 대해서 동일하게 적용된다.
public class MovieRecommender {
   private Set<MovieCatalog> movieCatalogs;
   @Autowired
   public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
      this.movieCatalogs = movieCatalogs;
   }
   // ...
}

심지어 Map 타입도 key 의 타입이 String인 경우에 자동으로 엮여질(autowired) 수 았다. Map의 value는 예상되는 타입의 모든 빈들을 포함하게 되며, key는 해당 bean의 이름들을 포함하게 된다.
public class MovieRecommender {
   private Map<String, MovieCatalog> movieCatalogs;
   @Autowired
   public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
      this.movieCatalogs = movieCatalogs;
   }
   // ...
}

기본적으로 자동 엮음(autowiring)은 가능한 빈드이 없다면 실패하게 된다. 기본적인 행위는 annotation이 있는 메소드, 생성자, 필드를 required 로 지정되어 있는 것으로 처리한다. 이러한 행위는 다음과 같이 변경이 가능하다.
public class SimpleMovieLister {
   private MovieFinder movieFinder;
   @Autowired(required=false)
   public void setMovieFinder(MovieFinder movieFinder) {
      this.moveFinder = movieFinder;
   }
   // ...
}

주의 - 클래스 당 오직 하나의 annotation이 있는 생성자만 required로 표기가 가능하며, 여러개의 필수가 아닌 생성자는 anootation이 가능하다. 이 경우, 각각은 주입이 가능한 빈들 사이에서 고려되어지며 Spring은 의존성이 만족될 수 있는 가장 필요한 생성자를 사용한다.

반응형