Spring框架笔记(十三)——注解配置bean时的自动装配问题

在使用注解方式进行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 注解




你可能感兴趣的:(Spring框架笔记(十三)——注解配置bean时的自动装配问题)