1.9 어노테이션 기반의 컨테이너 구성 by sh
어노테이션 기반의 컨테이너 구성
1.9. 어노테이션 기반의 컨테이너 구성
스프링을 구성하기 위해 XML보다 어노테이션이 더 유용합니까?
어노테이션 기반 구성의 도입으로 이 접근 법이 XML보다 “더 나은” 것인 지 여부에 대한 질문이 제기되었습니다. 간략한 대답은 “의존한다” 입니다. 긴 대답은 “각각의 접근 방식에 장단점이 있으며 일반적으로 어떤 전략이 더 적합한 지 결정하는 것은 개발자의 몫”입니다. 어노테이션이 정의된 방식으로 인해, 어노테이션은 선언문에 많은 문맥을 제공하므로 짧고 간결한 구성이 가능합니다. 그러나 XML은 소스 코드를 건드리거나 다시 컴파일 하지 않고도 구성 요소를 연결할 때 탁월합니다. 일부 개발자들은 소스에 가까운 배선을 선호하는 반면, 일부 다른 개발자들은 어노테이션이 달린 클래스는 더 이상 POJO가 아니며 구성이 분산되고 제어하기가 더 어려워 진다고 주장합니다.
(+)
XML Vs. Annotation
시스템 전반에 영향을 주는 메타데이터는 XML로 설정하여 코드로부터 독립적으로 분리되는 것이 바람직하다.
설계 시 확정되는 부분은 Annotation 기반 설정으로 개발의 생산성을 향상 시키는 것이 바람직하다.
POJO (= Plain Old Java Object)
순수 자바 객체 (순수하게 "setter"와 "getter"로 이루어진 Value Object성의 빈)
선택과 상관없이 스프링은 두 스타일을 모두 수용할 수 있으며 함께 혼합할 수도 있습니다. Java Config 옵션을 통해 스프링은 대상 구성 요소 소스 코드를 건드리지 않고 어노테이션을 비 침습적인 방법으로 사용할 수 있으며 툴링 측면에서 모든 구성 스타일이 Spring Tool Suite에서 지원된다는 점을 지적할 가치가 있습니다.
(+)
스프링의 Java Config 기능
XML이 아닌 자바 코드를 이용해서 컨테이너를 설정할 수 있는 기능.
Ex. @Configuration, @Bean
Cf. https://www.slideshare.net/arawnkr/spring-camp-2013-java-configuration
XML 설정의 대안은 어노테이션 기반 구성에 의해 제공됩니다. 이 구성은 꺽쇠 괄호 선언 대신 구성 요소를 연결하기 위해 바이트 코드 메타 데이터를 사용합니다. XML을 사용하여 Bean 배선을 설명하는 대신 개발자는 관련 클래스나 메소드 또는 필드 선언에 대한 어노테이션을 사용하여 구성을 구성 요소 클래스 자체로 이동합니다. 예제 RequiredAnnotationBeanPostProcess에서 언급한 것처럼, 어노테이션과 함께 BeanPostProcessor를 사용하는 것은 스프링 IoC 컨테이너를 확장하는 일반적인 방법입니다. 예를 들어, 스프링 2.0은 @Required 어노테이션으로 필수 속성을 적용할 수 있는 가능성을 소개했습니다. 스프링 2.5는 스프링의 의존성 삽입을 유도하는 일반적인 접근 방식을 따르는 것을 가능하게 했습니다. 본질적으로 @Autowired 어노테이션은 Autowiring Collaborators에서 설명한 것과 동일한 기능을 제공하지만, 보다 세분화된 제어와 폭 넓은 적용 가능성을 제공합니다. 스프링 2.5는 또한 @PostConstruct 및 @PreDestroy와 같은 JSR-250 어노테이션에 대한 지원을 추가했습니다. 스프링 3.0은 @Inject와 @Named와 같은 javax.inject 패키지에 포함된 JSR-330 (Dependency Injection for Java) 어노테이션을 지원했습니다. 이러한 어노테이션에 대한 자세한 내용은 관련 섹션에서 확인할 수 있습니다.
(+)
Annotation : 자바 소스 코드에 추가하여 사용하는 메타 데이터의 일종.
컴파일러에 의해 생성되는 .class 파일에 포함되며 그 .class 파일을 통해 읽혀진다. (클래스들과 마찬가지로 바이트 코드 파일로 컴파일 및 저장되기 때문에 일반 자바 객체와 마찬가지로 처리될 수 있음)
어노테이션 삽입은 XML 삽입 전에 수행됩니다. 따라서 XML 구성은 두 가지 접근 방식을 통해 연결된 속성에 대한 어노테이션을 대체합니다.
항상 그렇듯이, 개별 Bean 정의로 어노테이션을 등록할 수 있지만, 다음 태그를 XML 기반 스프링 구성에 포함하여 암시적으로 등록할 수도 있습니다. (context 네임스페이스 포함) :
(암시적으로 등록된 post-processor에는 AutowiredAnnotationBeanPostProcessor
,
CommonAnnotationBeanPostProcessor
,
PersistenceAnnotationBeanPostProcessor
및 앞서 언급했던
RequiredAnnotationBeanPostProcesso
가 포함됩니다
)
(+)
BeanPostProcessor
개발자가 원하는(또는 컨테이너의 기본 로직을 오버라이트하는) 인스턴스화 및 의존성 처리 로직 등을 구현할 수 있는 메소드를 정의하는 인터페이스.
<context:annotation-config/>의 추가를 통해, 어노테이션 관련하여 아래의 BeanPostProcessor들을 함께 등록하여 어노테이션을 인식하게 한다.
RequireAnnotationBeanPostProcessor -> @Required 처리
AutowiredAnnotationBeanPostProcessor -> @Autowired 처리
CommonAnnotationBeanPostProcessor -> @Resource, @PostConstruct, @PreDestroy 처리
ConfigurationClassBeanPostProcessor -> @Configuration 처리
!
<context:annotation-config/>는 이것이 정의된 동일한 응용 프로그램 컨텍스트에서의 빈들에 대한 어노테이션만 찾습니다. 즉, <context:annotation-config/>를 DispatcherServlet의 WebApplicationContext에 넣는다면, 서비스가 아니라 컨트롤러의 @Autowired Bean만 검사합니다. 자세한 정보는 DispatcherServlet 을 참조하십시오.
1.9.1. @Required
@Required
어노테이션은 다음 예제와 같이 빈 속성 setter 메소드에 적용됩니다 :
이 어노테이션은 영향을 받는 빈 프로퍼티가이 설정 시에 빈 정의의 명시적 프로퍼티 값이나 오토와이어링을 통해 채워 져야만 한다는 것을 의미합니다. 만일 영향을 받는 빈 프로퍼티가 채워지지 않는다면 컨테이너가 예외를 던집니다. 이것은 명시적으로 실패할 수 있으므로 NullPointerException
인스턴스를 피할 수 있습니다. Assertion을 Bean 클래스 자체에 넣는 것을 권장합니다. (예: init 메소드) 이렇게 하면 컨테이너 외부에서 클래스를 사용하는 경우에도 필요한 참조 및 값들이 적용됩니다.
1.9.2. Using @Autowired
JSR 330의 @Inject
어노테이션은 이 섹션에 포함된 예제에서 스프링의 @Autowired
어노테이션 대신 사용할 수 있습니다. 자세한 내용은 여기를 참조하십시오.
(+)
@Autowired Vs. @Inject
두 어노테이션 모두 타입에 의해 의존 관계를 자동을 연결해주는 기능을 한다.
@Autowired
스프링에서 등장한 어노테이션. 스프링 이외에서 사용 불가능.
@Inject
JSR에 실려 있는 자바 기반의 어노테이션. 스프링 이외에서도 사용 가능.
다음 예제와 같이 @Autowired
어노테이션을 생성자에 적용할 수 있습니다:
스프링 프레임워크 4.3에서, 타겟 빈이이 단지 하나의 생성자만을 정의한다면 그러한 생성자에 대한 @Autowired
어노테이션은 더 이상 필요하지 않습니다. 그러나 여러 생성자를 사용할 수 있는 경우에는, 사용할 컨테이너를 설명하기 위해 적어도 하나의 컨테이너에 어노테이션을 달아야 합니다.
다음 예제와 같이 @Autowired
어노테이션은 "전통적인" setter 메소드에도 적용할 수 있습니다:
다음의 예제 처럼, 임의의 이름 및 복수의 인수를 가지는 메소드에도 어노테이션을 적용할 수 있습니다:
@Autowired
를 필드에 적용할 수 있고 다음 예제와 같이 생성자와 혼합할 수도 있습니다:
타겟 컴포넌트(예: MovieCatalog
또는 CustomerPreferenceDao
)가 @Autowired
-annotated 주입 지점에 사용하는 타입에 따라 일관되게 선언되어 있는 지 확인하십시오. 그렇지 않으면, 실행 시 일치하는 타입이 없어 주입이 실패할 수 있습니다. 클래스 경로 검색을 통해 발견된 XML 정의된 빈 또는 컴포넌트 클래스들의 경우에 컨테이너는 일반적으로 구체적인 타입을 미리 알고 있습니다. 그러나, @Bean
팩토리 메소드의 경우에는 선언된 리턴 타입이 충분히 표현력이 있는 지 확인해야 합니다. 여러 인터페이스를 구현하는 컴포넌트 또는 해당 구현 타입에서 잠재적으로 참조되는 컴포넌트의 경우 팩토리 메소드에서 가장 구체적인 반환 타입을 선언하는 것을 고려하십시오. (최소한 해당 빈을 참조하는 주입 지점에서 요구되는 만큼 구체적으로)
다음의 예와 같이, 해당 타입의 배열을 필요로 하는 필드 또는 메소드에 어노테이션을 추가하는 것에 의해 ApplicationContext
로부터 특정한 타입의 빈들을 모두 제공할 수도 있습니다:
다음 예제와 같이 타입이 지정된 콜랙션에도 동일하게 적용됩니다:
배열이나 목록의 항목을 특정 순서로 정렬 하려면, 타겟 빈들이 org.springframework.core.Ordered
인터페이스를 구현하거나 @Order
또는 표준 @Priority
어노테이션을 사용할 수 있습니다. 그렇지 않은 경우, 그 순서는 컨테이너 내의 대응하는 타겟 빈 정의의 등록 순서를 따릅니다.
@Order
어노테이션은 대상 클래스 레벨과 @Bean
메소드에서 선언할 수 있으며 잠재적으로 개별 빈의 정의로 선언할 수 있습니다 (동일한 빈 클래스를 사용하는 여러 정의의 경우). @Order
값들은 주입 지점에서 우선 순위에 영향을 줄 수 있지만, 종속 관계 및 @DependsOn
선언에 의해 결정되는 직각적인 우려인 싱글톤 시작 순서에는 영향을 미치지 않습니다
표준 javax.annotation.Priority
어노테이션은 메소드에서 선언될 수 없기 때문에 @Bean
레벨에서 사용할 수 없습니다. 그것의 의미는 @Order
값을 @Primary
와 조합하여 각 타입에 대해 단일 빈에 모델링할 수 있습니다.
(+)
@Order
스프링 4에서 도입한 기능으로, 같은 타입의 빈이 콜렉션에 오토와이어드될 때 순서를 지정하는 기능을 한다. (낮은 순서가 우선 순위가 높음)
예견된 키 타입이 String
인 동안 타입화된 Map 인스턴스 조차 자동 실행될 수 있습니다. Map 값들은 예상되는 타입의 모든 빈을 포함하며, 키는 다음 예제와 같이 해당하는 빈의 이름을 포함합니다:
기본적으로, 오토와이어링은 사용 가능한 후보 빈이 없다면 실패하게 된다. 기본 동작은 어노테이션이 선언된 메소드, 생성자 및 필드를 Required로 지정되어 있는 것으로 처리합니다. 다음 예제에서 이 동작을 설명된 대로 변경할 수 있습니다:
(+)
@Autowired를 적용한 필드를 반드시 설정할 필요가 없는 경우에는, @Autowired의 "required" 속성 값을 "false"로 지정한다.
이렇게 지정된 경우에는, 해당 타입에 맞는 빈 객체가 존재하지 않는다해도 예외를 발생시키지 않는다.
클래스 당 하나의 어노테이션이 붙은 생성자만 required로 표기가 가능하지만, 필수가 아닌 여러개의 생성자에도 어노테이션을 붙일 수 있다. 이 경우에 각각은 주입이 가능한 빈들 사이에서 고려 되어지며 스프링은 의존성이 충족될 수 있는 가장 필요한 생성자를 사용합니다.
@Required
와 상관없이 @Autowired
의 “required” 속성은 권장됩니다. “required” 속성은 해당 프로퍼티가 오토와이어링 목적에는 필수가 아니라는 것을 나타냅니다. 오토와이어링을 할 수 없는 경우에 이 프로퍼티는 무시됩니다. 반면에, @Required
는 컨테이너에 의해 지원되는 어떤 방법으로든 설정한 속성을 적용한다는 점에서 더 강력합니다. 주입되는 값이 없다면, 그에 대응하는 예외가 발생합니다.
또는 다음 예제와 같이 Java 8의 java.util.Optional
을 통해 특정 종속성의 불필요한 특성을 표현할 수 있습니다:
(+)
Optional : NULL이 될 수도 있는 객체를 감싸고 있는 일종의 래퍼 클래스.
스프링 프레임워크 5.0에서 @Nullable
어노테이션을 사용할 수도 있습니다. (예: JSR-305의 javax.annotation.Nullable
과 같은 모든 패키지의 모든 종류):
BeanFactory
, ApplicationContext
, Environment
, ResourceLoader
, ApplicationEventPublisher
, and MessageSource
와 같이 잘 알려진 해결 가능한 종속성을 갖는 인터페이스에 @Autowired
를 사용할 수도 있습니다. 이러한 인터페이스와 ConfigurableApplicationContext
또는 ResourcePatternResolver
와 같은 확장 인터페이스는 특별한 설정이 필요 없이 자동으로 해결됩니다. 다음 예제에서는 ApplicationContext
객체를 오토와이어링합니다:
The @Autowired
, @Inject
, @Resource
, and @Value
어노테이션은 스프링 BeanPostProcessor
구현에 의해 처리됩니다. 즉, 자신의 BeanPostProcessor
또는 BeanFactoryPostProcessor
(있을 경우) 타입 내에 이러한 어노테이션을 적용할 수 없습니다. 이러한 타입들은 XML 또는 스프링 @Bean
메소드를 사용하여 명시적으로 “유선 연결”해야 합니다.
1.9.3. Fine-tuning Annotation-based Autowiring with @Primary
타입에 의한 오토와이어링은 여러 후보로 이어질 수 있으므로, 선택 프로세스를 더 잘 제어할 필요가 있습니다. 이를 수행하는 한 가지 방법이 스프링의 @Primary
어노테이션을 사용하는 것입니다. @Primary
는 여러 빈이 단일 값 종속성에 대해 오토와이어드 될 후보가 될 때 특정 빈에 우선 순위를 부여해야 함을 나타냅니다. 정확하게 하나의 primary 빈이 후보들 사이에 존재하면, 이것이 오토와이어드 된 값이 됩니다.
firstMovieCatalog
를 기본 MovieCatalog
로 정의하는 다음 구성을 고려하십시오:
앞의 구성에서 다음 MovieRecommender
는 firstMovieCatalog
이 자동 주입됩니다:
해당 빈의 정의는 다음과 같습니다:
1.9.4. Fine-tuning Annotation-based Autowiring with Qualifiers
@Primary
는 하나의 기본 후보가 결정될 수 있을 때 여러 개의 인스턴스와 함께 타입에 의한 오토와이어링을 사용하는 효과적인 방법입니다. 선택 프로세스에 대한 더 많은 제어가 필요한 경우 스프링의 @Qualifier
어노테이션을 사용할 수 있습니다. qualifier 값을 특정 인수와 연관시켜 타입 일치 집합을 좁혀 특정 인수가 각 인수에 대해 선택되도록 할 수 있습니다. 가장 단순한 경우, 다음 예제와 같이 일반적인 설명 값이 될 수 있습니다:
다음 예제와 같이 개별 생성자 인수 또는 메서드 매개 변수에 @Qualifier
어노테이션을 지정할 수도 있습니다:
다음 예제는 해당 빈의 정의를 보여줍니다.
"main” qualifier 값을 가진 빈은 동일한 값으로 규정된 생성자 인수와 연결됩니다.
"action" qualifier 값을 가진 빈은 동일한 값으로 규정된 생성자 인수와 연결됩니다.
폴백 일치의 경우(일치하는 값을 찾지 못했을 때를 대비해서) 빈 이름이 기본 규정 자(qualifier) 값으로 간주됩니다. 따라서, 중첩된 qualifier 요소 대신에 id가 “main
”인 빈을 정의해도 동일한 결과를 얻을 수 있습니다. 하지만 이름으로 특정 빈을 참조하는 이 관례를 사용할 수 있더라도 본질적으로 @Autowired
는 추가적인 의미 있는 qualifier를 사용하는 타입 기반의 주입에 대한 것입니다. 즉, 실패했을 때(fallback) 빈 이름을 사용하더라도 qualifier 값은 항상 일치된 타입의 세트 내에서 의미로 제한한다는 의미입니다. 그들은 유일한 빈 id에 대한 참조를 의미론적으로 표현하지 않습니다. 앞의 예제처럼 익명의 빈 정의의 경우에 자동으로 생성되는 빈 id와는 독립적으로 특정 컴포넌트의 특징을 표현하는 main
또는 EMEA
또는 persistent
가 좋은 qualifier 값입니다.
앞서 애기했듯이 qualifier는 Set 같은 타입 있는 컬렉션에도 적용됩니다. 이 경우에 선언된 qualifier에 일치하는 모든 빈이 컬렉션으로 주입됩니다. 이는 qualifier는 유일할 필요가 없다는 의미입니다. 오히려 필터링 기준을 구성합니다. 예를 들어 “action”이라는 동일한 qualifier 값을 가진 여러 개의 MovieCatalog
빈을 정의할 수 있습니다. 이 빈들은 모두 @Qualifier("action")
어노테이션이 붙은 Set로 주입될 것입니다.
타입이 일치하는 후보 빈들 내에서 대상 빈 이름에 대해 qualifier 값을 선택하게 하면, 주입 지점에 @Qualifier
어노테이션이 필요하지 않습니다. 유일하지 않은 의존성 상황에 대해 다른 해결 지시자(예: qualifier 또는 primary 표시)가 없다면, 스프링은 대상 빈 이름에 대해 주입 지점 이름 (즉, 필드 이름 또는 매개 변수 이름)을 일치 시킵니다.
이름으로 어노테이션 중심의 주입을 표현하려는 경우, @Qualifier
값으로 빈 이름을 참조하는 것이 기술적으로 가능하더라도 @Autowired
를 주로 사용하지 마십시오. 대신, 의미적으로 유일한 이름의 특정 대상 컴포넌트를 식별하기 위해 정의된 JSR-250 @Resource
어노테이션을 사용하십시오. 선언된 타입은 일치하는 빈을 찾는 과정과는 관계가 없습니다. @Autowired
는 다소 다른 의미를 가지고 있습니다. 타입에 의해 후보 빈을 선택한 후, 지정된 String
qualifier 값은 해당 타입의 선택된 후보 내에서만 고려됩니다. (예: 동일한 qualifier 레이블로 표시된 빈에 대한 계정 qualifier 일치)
(+) @Autowired Vs. @Resource
공통 : 적절한 의존 객체를 빈 객체들 중에서 찾아 주입
차이 : 빈 객체의 id와 class 중 어떤 것을 우선하여 검색하는 지에 대해 차이가 존재
@Autowird : 스프링이 타입(class)을 우선으로 빈 객체를 검색
@Resource : 스프링이 이름(id)을 우선으로 빈 객체를 검색
-> 이름으로 찾을 거면, 타입 우선인 Autowired를 사용하지 말고 차라리 Resource를 사용하는 을 권장.
콜렉션, Map, 또는 배열 타입으로 정의된 빈의 경우 @Resource
는 고유한 이름으로 특정 Collection 또는 배열 빈을 참조하는 좋은 솔루션입니다. 즉, 4.3의 컬렉션에서 @Bean
반환 타입 시그니처 또는 컬렉션 상속 계층 구조에서 요소 타입 정보가 유지되는 한 Map 및 배열 타입을 스프링의 @Autowired
타입 일치 알고리즘과 일치시킬 수 있습니다. 이 경우 qualifier 값을 사용하여 이전 단락에서 설명한대로 동일한 타입의 콜렉션 중에서 선택할 수 있습니다.
4.3에서 @Autowired
는 또한 주입에 대한 자체 참조(즉, 현재 주입된 빈에 대한 참조)를 고려합니다. 셀프 주입은 대체적인 기능입니다. 다른 컴포넌트에 대한 정기적인 종속성이 항상 우선합니다. 이러한 의미에서 자체 참조는 정기적인 후보자 선정에 참여하지 않아서 특히 중요하지 않습니다. 반대로, 그들은 항상 최우선 순위로 끝납니다. 실제로, 셀프 참조는 마지막 수단으로만 사용해야 합니다. (예: 빈의 트랜잭션 프록시를 통해 동일한 인스턴스의 다른 메소드를 호출하는 경우) 이러한 시나리오에서 영향을 받은 메소드를 별도의 delegate 빈으로 분해하는 것을 고려하십시오. 또는 @Resource
를 사용할 수 있습니다. @Resource
는 고유의 이름으로 현재 빈으로 프록시를 다시 가져올 수 있습니다.
@Autowired
는 필드, 생성자 및 다중 인수 메서드에 적용되므로 매개 변수 수준에서 qualifier 어노테이션을 좁힐 수 있습니다. 반대로 @Resource
는 단일 인수를 사용하는 필드 및 빈 등록 정보 설정 메소드에서만 지원됩니다. 따라서 주입 대상이 생성자 또는 다중 인수 메서드인 경우 qualifier를 사용해야 합니다.
(+) @Autowired 및 @Resource 적용 순서
고유의 사용자 정의 qualifier 어노테이션을 만들 수 있습니다. 이렇게 하려면, 다음 예제와 같이 어노테이션을 정의하고 정의 내에서 @Qualifier
어노테이션을 제공하십시오:
(+) 어노테이션 커스터마이징에 사용하는 메타 데이터
@Target : 어디에 선언?
ElementType.TYPE : 클래스, 인터페이스, enum 선언부
ElementType.CONSTRUCTOR : 생성자 선언부
ElementType.LOCAL_VARIABLE : 지역 변수 선언부
ElementType.METHOD : 메소드 선언부
ElementType.PACKAGE : 패키지 선언부
ElementType.PARAMETER : 파라미터 선언부
@Retention : 유지 방식은?
RetentionPolicy.RUNTIME : 컴파일러에 의해 class 파일에 추가되고 런타임 시 VM에서 유지
RetentionPolicy.SOURCE : 컴파일 시 class 파일에 추가되지 않는다.
RetentionPolicy.CLASS : 클래스 안에 애노테이션이 추가되지만 런타임 시 VM에서는 사용되지 않는다.
그런 다음, 다음의 예제와 같이 오토와이어드 된 필드 및 매개 변수에 사용자 지정 qualifier를 제공할 수 있습니다:
다음 단계는 자동 엮어질 후보 빈 정의에 해당 정보를 추가하는 것입니다. <qualifier/>
태그를 <bean/>
태그의 하위 요소로 추가한 다음, 사용자 정의 qualifier 어노테이션과 일치하도록 type
및 value
을 지정할 수 있습니다. 타입은 어노테이션의 패키지를 포함한 전체 클래스 명과 일치합니다. 또는, 이름이 충돌하는 위험이 없다면 ‘짧은’ 클래스 이름을 사용할 수 있습니다. 다음 예제는 두 가지 접근 방법을 보여줍니다:
Classpath Scanning and Managed Components (1.10) 에서는 XML로 qualifier 메타데이터를 제공하는 어노테이션 기반의 대안을 볼 수 있습니다. 구체적으로는 Providing Qualifier Metadata with Annotations를 참조하십시오.
경우에 따라서는 값 없이 어노테이션을 사용하는 것으로 충분할 수 있습니다. 이것은 어노테이션이 보다 일반적인 목적을 위해 사용되고 여러 개의 다른 타입의 종속성으로 적용될 수 있을 때 유용할 수 있습니다. 예를 들어, 인터넷 연결이 불가능할 때 검색될 수 있는 Offline 카탈로그를 제공할 수 있습니다. 먼저, 다음 예제와 같이 간단한 어노테이션을 정의합니다.
그런 다음, 다음 예제와 같이 어노테이션을 오토와이어드할 필드 또는 속성에 추가하십시오:
이 라인에 @Offline
어노테이션을 추가합니다.
이제 빈의 정의는 다음 예와 같이 qualifier 타입만 필요합니다:
이 요소는 qualifier를 구체화합니다.
간단한 값 속성 대신에 이름이 지정된 속성을 허용하는 qualifier 어노테이션을 정의할 수도 있습니다. 만일 여러 개의 속성 값들이 자동 엮어질 필드나 매개 변수에 지정된다면, 빈 정의는 오토와이어링 대상이라고 생각되는 모든 속성 값과 일치해야 합니다. 예를 들어, 다음 어노테이션 정의를 고려하십시오:
이 경우 Format
은 다음과 같이 정의되는 enum 입니다:
오토와이어링 할 필드는 사용자 정의 qualifier가 어노테이션으로 지정되며 다음 예제와 같이 두 개의 속성(genre
, format
)에 대한 값이 포함됩니다:
마지막으로, 빈 정의는 qualifier 값들에 대한 일치하는 것들을 포함해야 합니다. 이 예제에서는 또한 <qualifier/>
요소 대신 빈 메타 속성이 사용될 수 있음을 보여줍니다. 가능하다면, <qualifier/>
요소와 그것의 속성들이 우선권을 가지지만, 자동 엮음 메커니즘은 qualifier가 존재하지 않는다면 <meta/>
태그 내에서 제공되는 값을 대신 사용하게 됩니다. (마지막 2개의 빈 정의 참조):
1.9.5. Using Generics as Autowiring Qualifiers
@Qualifier
어노테이션 외에도 암시적인 형태의 자격으로 자바 제네릭 타입을 사용할 수 있습니다. 예를 들어, 다음 구성을 가지고 있다고 가정합니다:
(+) 스프링 4.0 부터 자바 제네릭 입을 주입받을 수 있음. (4.0 미만도 가능은 했지만 번거로운 추가 작업이 필요)
(+) stringStor, integerStore 가 해당 빈을 나타내는 qualifier라고 생각하면 됨.
(+) 반환 타입은 Store<T>
앞의 빈이 제네릭 인터페이스(즉, Store<String>
and Store<Integer>
)를 구현한다고 가정하면, 다음 예제와 같이 Store 인터페이스를 호출하고 제네릭이 qualifier로 사용됩니다:
제네릭 qualifier는 리스트, 맵 인스턴스, 배열을 오토와이어링할 때에도 적용됩니다. 다음 예제에서는 제네릭 리스트를 오토와이어링합니다:
1.9.6. Using CustomAutowireConfigurer
CustomAutowireConfigurer
는 BeanFactoryPostProcessor
로, 사용자 정의 qualifier 어노테이션 타입을 스프링의 @Qualifier
로 어노테이션 처리하지 않고도 등록할 수 있습니다. 다음 예제에서는 CustomAutowireConfigurer
를 사용하는 방법을 보여줍니다:
(+)
CustomAutowireConfigurer
가BeanFactoryPostProcessor
를 구현함.BeanFactoryPostProcessor
의CustomAutowireConfigurer
유형을 편리하게 등록할 수 있는 구현임.BeanFactoryPostProcessor
: 컨텍스트의 기본 빈 펙토리의 빈 특성 값을 적용하여 응용 프로그램 컨텍스트의 빈 정의를 사용자 정의하여 수정할 수 있도록 하는 인터페이스. (순서 등)
AutowireCandidateResolver
는 오토와이어링 후보를 다음과 같이 결정합니다:
각 빈 정의의
default-autowire-candidates
값 (자바 5 이전 버전)요소에서 사용 가능한 모든
default-autowire-candidates
패턴 (자바 5 이전 버전)@Qualifier
어노테이션과CustomAutowireConfigurer
에 등록된 모든 사용자 지정 어노테이션의 존재 (자바 5 이상의 버전)(+) 자바 5 이전의 버전은 qualifier 어노테이션을 지원하지 않음.
자바 버전에 상관없이 여러 개의 빈이 오토와이어링 후보로 자격이 주어졌을 때, “primary” 후보가 결정되는 방식은 동일합니다 : 후보 중 정확하게 primary 속성이 true로 설정된 빈이 있다면, 이것이 선택됩니다.
1.9.7. Injection with @Resource
스프링은 필드 또는 빈 속성 setter 메소드에서 JSR-250 @Resource
어노테이션을 사용하여 주입을 지원합니다. 이는 Java EE 5 및 6 (예: JSF 1.2 관리 빈 또는 JAX-WS 2.0 엔드 포인트)의 공통 패턴입니다. 스프링은 스프링 관리 객체에 대해서도 이 패턴을 지원합니다
@Resource
는 name 속성을 취합니다. 기본적으로 스프링은 그 값을 주입할 빈 이름으로 해석합니다. 즉, 다음 예에서와 같이 이름 별 의미 체계를 따릅니다:
이 라인에 @Resource
를 주입합니다.
이름을 명시적으로 지정하지 않으면, 기본 이름이 필드 이름 또는 setter 메소드에서 파생됩니다. 필드의 경우, 필드 이름이 필요합니다. Setter 멧드의 경우, 빈 속성 이름을 사용합니다. 다음 예제에서는 setter 메소드에 삽입된 movieFinder
라는 빈을 갖게 됩니다:
어노테이션으로 제공된 이름은 CommonAnnotationBeanPostProcessor
가 인식하는 ApplicationContext
에 의해 빈 이름으로 해석됩니다. 만일 스프링의 SimpleJndiBeanFactory
가 명시적으로 설정되어 있다면, 이름은 JNDI를 통해 처리될 수 있습니다. 그러나, 기본적인 동작에 의존하고 간접적인 수준을 유지하기 위해 스프링의 JADI 검색 기능을 간단히 사용하기를 권장합니다.
(+) JNDI (Java Naming and Directory Interface)
이름과 객체를 매핑 시켜주는 Naming Service를 감싸는 인터페이스 집합으로서, 표준 방법을 통해 naming 서비스에 접근할 수 있도록 해준다.
명시적으로 이름을 지정하지 않고 @Autowired
와 비슷한 @Resource
사용의 독점적인 경우, @Resource
는 특정하게 이름 붙여진 빈 대신 일치하는 주요 타입을 찾고 잘 알려진 해결할 수 있는 의존성을 해결합니다. 잘 알려진 해결할 수 있는 의존성은 BeanFactory
,ApplicationContext
, ResourceLoader
, ApplicationEventPublisher,
MessageSource
인터페이스들입니다.
그러므로 다음 예제에서 customerPreferenceDao
필드는 customerPreferenceDao 라는 이름의 빈을 먼저 찾고, 못 찾으면 customerPreferenceDao
타입과 일치하는 주요 타입을 찾습니다:
context
필드는 알고 있는 해결할 수 있는 의존성 타입인 ApplicationContext
에 기반해서 주입됩니다.
1.9.8. Using @PostConstruct and @PreDestroy
CommonAnnotationBeanPostProcessor
는 @Resource
어노테이션 뿐만 아니라 JSR-250 라이프 사이클 어노테이션을 인식합니다. 스프링 2.5에서 소개된 이 어노테이션에 대한 지원은 ininitialization callbacks와 destruction callbacks에서 설명한 것에 대한 또 다른 대안을 제공합니다. CommonAnnotationBeanPostProcessor
가 스프링 ApplicationContext
내에 등록되어 있으면, 이러한 어노테이션 중 하나를 전달하는 메서드는 해당 라이프 사이클 인터페이스 메소드 또는 명시적으로 선언된 콜백 메소드와 같은 라이프 사이클의 동일한 지점에서 호출됩니다. 다음 예제에서, 캐시는 초기화 시에 미리 populate되고, 삭제 시에 clear됩니다:
(+)
PostConstruct And. @PreDestroy
@PostConstruct : 객체(빈)가 생성된 후 별도의 초기화 작업을 위해 실행하는 메소드를 선언한다.
Cf. 초기화 메서드 : 빈 객체가 생성되고 DI 작업까지 마친 다음 실행되는 메서드. (기본적으로 객체의 초기화 작업은 생성자에서 진행하지만, DI를 통해 빈이 주입된 후에 초기화할 작업이 있을 경우, 초기화 메서드를 이용)
@PreDestroy : 스프링 컨테이너에서 객체(빈)를 제거하기 전에 해야 할 작업이 있을 때 실행하는 메소드를 선언한다.
(공통) CommonAnnotationBeanPostProcessor 클래스를 빈으로 등록시키거나 <context:annotation-config/>태그를 사용하면 된다.
다양한 라이프 사이클 메커니즘 결합의 효과에 대한 자세한 내용은 Combining Lifecycle Mechanisms를 참조하십시오.
Last updated
Was this helpful?