2. 따라서 java class에서 @Autowired를 사용했다.
3. 하지만, 1번 xml 문서의 14라인의 새로운 이름의 MessageBean에 대한 bean이 존재하게 될 경우 아래와 같은 에러가 발생하게 된다.
정보: Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@15eb0a9: display name [org.springframework.context.support.FileSystemXmlApplicationContext@15eb0a9]; startup date [Thu Aug 13 17:44:54 KST 2009]; root of context hierarchy
2009. 8. 13 오후 5:44:54 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
정보: Loading XML bean definitions from file [C:\JSP\Spring\src\newanno\newaano.xml]
2009. 8. 13 오후 5:44:54 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
정보: Bean factory for application context [org.springframework.context.support.FileSystemXmlApplicationContext@15eb0a9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@111a775
2009. 8. 13 오후 5:44:54 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
정보: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@111a775: defining beans [org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,new,message,message2]; root of factory hierarchy
2009. 8. 13 오후 5:44:54 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
정보: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@111a775: defining beans [org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,new,message,message2]; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'new': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void newanno.NewAnnoImp.setBean(newanno.MessageBean); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [newanno.MessageBean] is defined: expected single matching bean but found 2: [message, message2]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:256)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:998)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
at newanno.AnnoTest.main(AnnoTest.java:9)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void newanno.NewAnnoImp.setBean(newanno.MessageBean); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [newanno.MessageBean] is defined: expected single matching bean but found 2: [message, message2]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
at org.springframework.beans.factory.annotation.InjectionMetadata.injectMethods(InjectionMetadata.java:117)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:253)
... 16 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [newanno.MessageBean] is defined: expected single matching bean but found 2: [message, message2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:621)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:499)
... 18 more
4.여기에 대한 해결 방법은 @Qualifier 이다.
xml문서의 bean들에 qualifier value값을 정의하고, class파일에서 해당 value 값을 적어 줌으로써 원하는 bean을 참조할 수 있다.
5. 응용
더보기
※ 참고사이트
@Autowiredhttp://homo-ware.tistory.com/14
@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은 의존성이 만족될 수 있는 가장 필요한 생성자를 사용한다.
Qualifier를 사용하는 annotation 기반 자동엮음(autowiring) 세부 조정
타입에 의한 자동엮음(autowiring)은 여러개의 빈이 엮여질 수 있기 때문에 선택 과정에 대해서 좀 더 제어를 할 필요가 종종 있다. 이를 하기 위한 한가지 방법은 Spring의 @Qualifier annotation을 사용하는 것이다. 가장 단순한 경우, annotation 내의 빈 이름을 써서 byName 자동엮음을 할 수 있다.
public class MovieRecommender {
@Autowired
@Qualifier("mainCatalog")
private MovieCatalog movieCatalog;
// ...
}
@Qualifier annotation은 또한 개개의 생성자 인자나 메소드 파라미터에 지정이 가능하다.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("mainCatalog") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
또한 사용자에 맞는 qualifier annotation을 만들 수도 있다. 단순하게 annotation을 정의하고 정의 내에 @Qualifier annotation을 쓰면 된다.
@Target({ElementType.FIELD, ElementType.PARAMETER})그 다음에 자동엮음을 하려는 필드와 파라미터에 만들어진 qualifier를 적용할 수 있다.
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value();
}
public class MovieRecommender {다음 단계는 자동엮여질 후보 빈 정의에 해당 정보를 추가하는 것이다. <bean/> 태그의 하위 요소로 <qualifier/> 태그를 추가하고 나서 만들어진 qualifier annotation과 일치하는 'type'과 'value'를 지정한다. type은 annotation의 패키지를 포함한 전체 클래스명과 일치하거나, 이름이 충돌날 염려가 없는 경우에는 '짧은' 클래스명을 사용할 수 있다.
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy")
MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
<?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/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
어떤 경우에는 value 없이 annotation을 사용하는 것으로 충분한 경우가 있다. 이는 annotation이 좀 더 일반적인 목적으로 사용되고 몇몇 다른 type의 의존성으로 적용될 때 유용하다. 예를 들어, 어떠한 인터넷 연결이 안되었을 때에 검색될 수 있는 offline 카탈로그를 제공할 수도 있다. 먼저 단순한 annotation을 다음과 같이 정의한다.
@Target({ElementType.FIELD, ElementType.PARAMETER})그 다음에 자동엮여질 필드나 속성에 annotation을 추가한다.
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
public class MovieRecommender {이제 빈 정의는 qualifier 'type' 만 필요하다.
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}
<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/>
<!-- inject any dependencies required by this bean -->
</bean>
추가로 혹은 단순한 'value' 속성 대신에 이름이 지정된 속성을 받아들이는 qualifier annotation을 정의할 수도 있다. 만일 여러개의 속성 값들이 자동엮여질 필드나 파라미터에 지정된다면 빈 정의는 자동엮음 대상이라고 생각되는 속성 값 모두와 일치해야 한다. 예를 들어, 다음과 같은 annotation 정의를 생각할 수 있다.
@Target({ElementType.FIELD, ElementType.PARAMETER})이 경우 Format은 다음과 같은 enum 이다.
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}
public enum Format {마지막으로 빈 정의는 qualifier 값들에 대한 일치하는 것을 포함해야 한다. 이 예제에서는 또한 bean의 meta 속성이 <qualifier/> 하위 요소 대신에 사용될 수 있음을 보여준다. 가능하다면, <qualifier/> 와 그 속성들이 우선시되지만, 자동엮음 메커니즘은 qualifier 가 존재하지 않는다면 <meta/> 태그 내에서 제공되는 값을 대신 사용하게 된다. (마지막 2개의 빈 정의 참조)
VHS, DVD, BLURAY;
}
<?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/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute name="format" value="VHS"/>
<attribute name="genre" value="Action"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute name="format" value="VHS"/>
<attribute name="genre" value="Comedy"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
<bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
<bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
<bean>
</beans>

























