在使用注解方式进行bean配置时,看起来十分方便,就如同上一篇博客介绍的那样。但是,如果我们bean类中的某个属性是另一个bean,应该怎么用注解的方式进行表示呢?
这就需要进行组件装配。
<context:component-scan> 元素除了会自动注册之前介绍的注解的实例,还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性.
我们这里着重介绍使用 @Autowired 自动装配 Bean
@Autowired 注解自动装配具有兼容类型的单个 Bean属性
构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false
默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 这时候,如果注解标识的bean名称与相关引用该bean的类的属性名称相同,则也能够自动装配上,即使存在多个类型兼容的类。但如果名称不一致,此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称(本文出自:http://my.oschina.net/happyBKs/blog/482493)
@Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配.
@Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.
@Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
好,我们还是用一组例子举一反三:
与上一篇博客中介绍的那样,我们按照一般系统的层次结构,定义来了一组类:
package com.happyBKs.annotations.beans; import org.springframework.stereotype.Component; @Component public class PositionBean { }
package com.happyBKs.annotations.controllers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import com.happyBKs.annotations.services.PositionService; @Controller public class PositionController { @Autowired PositionService positionService; public void execute() { System.out.println("PositionController execute..."); positionService.add(); } }
package com.happyBKs.annotations.respository; public interface PositionRespository { void save(); }
package com.happyBKs.annotations.respository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.happyBKs.annotations.beans.PositionBean; @Repository("positionRespository") public class PositionRespositoryImpl implements PositionRespository { @Autowired PositionBean positionBean; public void save() { // TODO Auto-generated method stub System.out.println("PositionRespository save..."); System.out.println(positionBean); } }
package com.happyBKs.annotations.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.happyBKs.annotations.respository.PositionRespository; import com.happyBKs.annotations.respository.PositionRespositoryImpl; @Service public class PositionService { PositionRespository positionRespository; @Autowired public void setPositionRespository(PositionRespository positionRespository) { this.positionRespository = positionRespository; } public void add() { System.out.println("PositionService save..."); positionRespository.save(); } }
这值得注意的是,@Autowired注解可以用在类的字段上(无论访问权限是什么),也可以放在字段的set方法上。
只要IOC容器中有相应类型的bean,spring就会自动为其装配。
IOC容器配置文件:
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 指定Spring IOC容器扫描的包 --> <context:component-scan base-package="com.happyBKs.annotations"></context:component-scan> </beans>
测试代码:
@Test public void test2() { ApplicationContext ac=new ClassPathXmlApplicationContext("beans-annotation.xml"); PositionController pc=(PositionController)ac.getBean("positionController"); System.out.println(pc); pc.execute(); }
输出结果:运行正常
com.happyBKs.annotations.controllers.PositionController@6dbb2d63
PositionController execute...
PositionService save...
PositionRespository save...
com.happyBKs.annotations.beans.PositionBean@1ba0f6dd
反三开始了。
1 如果属性的相应类型的bean在IOC容器中不存在会怎么样?
报错。
如果我将PositionBean的@Component去掉,那么IOC容器中将不会存在一个PositionBean类型的bean。那么,报错如下:
七月 22, 2015 5:49:04 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4595bfcd: startup date [Wed Jul 22 17:49:04 CST 2015]; root of context hierarchy 七月 22, 2015 5:49:04 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans-annotation.xml] 七月 22, 2015 5:49:05 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.services.PositionService com.happyBKs.annotations.controllers.PositionController.positionService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionRespository': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.happBKs.spring.iocaop.TestAnnotation.test2(TestAnnotation.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.services.PositionService com.happyBKs.annotations.controllers.PositionController.positionService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionRespository': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 36 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionRespository': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533) ... 38 more Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionRespository': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:649) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 49 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionRespository': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:606) ... 51 more Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.beans.PositionBean com.happyBKs.annotations.respository.PositionRespositoryImpl.positionBean; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 62 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.beans.PositionBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533) ... 64 more
也就是说所有配置了@Autowired的属性的类型的bean的类都需要确保已经被配置成。
2 如果我们需要某些属性自动装配时,如果IOC容器中不存在可以为空该怎么办?
将相应属性或set方法的@Autowired注解设置它的require参数为false。
package com.happyBKs.annotations.respository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.happyBKs.annotations.beans.PositionBean; @Repository("positionRespository") public class PositionRespositoryImpl implements PositionRespository { @Autowired(required=false) PositionBean positionBean; public void save() { // TODO Auto-generated method stub System.out.println("PositionRespository save..."); System.out.println(positionBean); } }
然后在运行测试程序,输出结果:正常运行
com.happyBKs.annotations.controllers.PositionController@1ba0f6dd
PositionController execute...
PositionService save...
PositionRespository save...
null
3 标注了@Autowired的属性对应的类型如果在IOC容器中有两个bean,在这种注解方式定义bean的方式中,那该怎么办呢?
spring首先回去检查这个两个bean的id的名字是否与这个@Autowired的属性的名字相同,从中选择那个名字相同的bean;如果两个bean的名字与这个注解了@Autowired的属性名字都不相同,则会报错!这时候,需要在注解了@Autowired的属性上再注解一个
首先,我们先加入一个类:
package com.happyBKs.annotations.respository; import org.springframework.stereotype.Repository; @Repository public class PositioinDAOImpl implements PositionRespository { public void save() { // TODO Auto-generated method stub System.out.println("PositioinDAOImpl save..."); } }
这样,PositionService的
PositionRespository positionRespository; @Autowired public void setPositionRespository(PositionRespository positionRespository) { this.positionRespository = positionRespository; }
就会两个类型匹配的bean在IOC容器中。
但是PositionRespositoryImpl类对应的bean的id是positionRespository,与PositionService的set属性名一致。
@Repository("positionRespository") public class PositionRespositoryImpl implements PositionRespository {
所以,这里既是bean类型都匹配PositionRespository接口,也不会发生错误。
测试程序运行结果如下:
com.happyBKs.annotations.controllers.PositionController@6e689e6e
PositionController execute...
PositionService save...
PositionRespository save...
null
但是,如果我把PositionRespositoryImpl的@Autowired注解定义的bean的id去掉,那么PositionRespositoryImpl类对应的bean的id就是positionRespositoryImpl。这样PositionService则无法决定装配positionRespositoryImpl还是装配PositioinDAOImpl了,因为他俩都是PositionRespository接口类型并且对应的bean的id名字与PositionService的positionRespository属性名字都不相同。
package com.happyBKs.annotations.respository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.happyBKs.annotations.beans.PositionBean; @Repository public class PositionRespositoryImpl implements PositionRespository { @Autowired(required=false) PositionBean positionBean; public void save() { // TODO Auto-generated method stub System.out.println("PositionRespository save..."); System.out.println(positionBean); } }
这时候,运行策会报错:
七月 22, 2015 8:22:38 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@516fa2a5: startup date [Wed Jul 22 20:22:38 CST 2015]; root of context hierarchy 七月 22, 2015 8:22:38 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans-annotation.xml] 七月 22, 2015 8:22:39 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.services.PositionService com.happyBKs.annotations.controllers.PositionController.positionService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.respository.PositionRespository] is defined: expected single matching bean but found 2: positioinDAOImpl,positionRespositoryImpl at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.happBKs.spring.iocaop.TestAnnotation.test2(TestAnnotation.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.happyBKs.annotations.services.PositionService com.happyBKs.annotations.controllers.PositionController.positionService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.respository.PositionRespository] is defined: expected single matching bean but found 2: positioinDAOImpl,positionRespositoryImpl at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 36 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'positionService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.respository.PositionRespository] is defined: expected single matching bean but found 2: positioinDAOImpl,positionRespositoryImpl at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533) ... 38 more Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.happyBKs.annotations.services.PositionService.setPositionRespository(com.happyBKs.annotations.respository.PositionRespository); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.respository.PositionRespository] is defined: expected single matching bean but found 2: positioinDAOImpl,positionRespositoryImpl at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:649) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ... 49 more Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.happyBKs.annotations.respository.PositionRespository] is defined: expected single matching bean but found 2: positioinDAOImpl,positionRespositoryImpl at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:606) ... 51 more
如果我们希望PositionService自动装配时不要因为知道加载哪个bean而报错,我们就需要用另一个注解——@Qualifier来指定需要装配的bean的id。
这里可以写为:
package com.happyBKs.annotations.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import com.happyBKs.annotations.respository.PositionRespository; import com.happyBKs.annotations.respository.PositionRespositoryImpl; @Service public class PositionService { PositionRespository positionRespository; @Autowired @Qualifier("positionRespositoryImpl") public void setPositionRespository(PositionRespository positionRespository) { this.positionRespository = positionRespository; } public void add() { System.out.println("PositionService save..."); positionRespository.save(); } }
这时候,运行结果就正确了:
com.happyBKs.annotations.controllers.PositionController@53497f3c
PositionController execute...
PositionService save...
PositionRespository save...
null
补充内容:
Spring 还支持 @Resource 和 @Inject 注解,这两个注解和 @Autowired 注解的功用类似
@Resource 注解要求提供一个 Bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 Bean 的名称
@Inject 和 @Autowired 注解一样也是按类型匹配注入的 Bean, 但没有 reqired 属性
建议使用 @Autowired 注解