Spring框架可以使用传统的xml文件方式来配置Bean,但是同样支持注解的方式配置Bean.本次主要将通过Spring注解方式(@Autowired和@Qualifier)来配置Bean。
储备知识:Spring Bean的配置方式有物种方式,根据autowired的取值可以分为no(通过ref指定),byType(根据依赖对象的类型),ByName(根据依赖对象的对象名在xml文件中找与之匹配的Bean),constructor(通过构造函数),autodetect(自动检测,先是byType后byName)。
当我们知道以上集中配置方式时,现在介绍@Autowire配置方式,是根据byType进行装配Bean的。
那么@Autowired可以作用在哪些地方呢:答案是可以作用在类的属性,setter方法,以及构造函数。
比如:如果类的一个属性上有@Autowired那么就表示该属性通过byType进行注入。
具体实例:
创建一个Customer对象:
对象含有Person对象引用;并且该属性通过@Autowired注入
public class Customer {
//测试spring注解方式
@Autowired()
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public Customer() {
}
@Override
public String toString() {
this.getPerson().toString();
return super.toString();
}
}
Customer的Bean配置信息:
<bean id="CustomerBean" class="scuec.test.springDI.Customer"/>
<bean id="zhangsan" class="scuec.test.spring.bean.Person">
<property name="name" value="张三"/>
<property name="age" value="20"/>
</bean>
Person类:
public class Person {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Person() {
}
@Override
public String toString() {
System.out.println("Person:"+this.getClass()+",Name:"+this.getName()+",Age:"+this.getAge());
return "Person:"+this.getClass()+",Name:"+this.getName()+",Age:"+this.getAge();
}
}
测试运行代码:
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Customer cus = (Customer)app.getBean("CustomerBean");
System.out.println(cus);//这里修改了cus.toString()方法
运行结果:
Person:class scuec.test.spring.bean.Person,Name:张三,Age:20
scuec.test.spring.bean.Customer@1a1d6a08
可以看出,Customer的Bean中并没有指定property属性为person,但是还是成功注入了。这就是因为通过@Autowired注解进行byType方式进行注入。在注入的时候会在bean容器中选择Person类型的对象进行注入。
那么问题来了,如果含有多个Person的对象会怎么样?配置文件如下:
<bean id="CustomerBean" class="scuec.test.spring.bean.Customer"/>
<bean id="zhangsan" class="scuec.test.spring.bean.Person">
<property name="name" value="张三"/>
<property name="age" value="20"/>
</bean>
<bean id="lisi" class="scuec.test.spring.bean.Person">
<property name="name" value="李四"/>
<property name="age" value="24"/>
</bean>
错误如下:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CustomerBean': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private scuec.test.spring.bean.Person scuec.test.spring.bean.Customer.person; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [scuec.test.spring.bean.Person] is defined: expected single matching bean but found 2: zhangsan,lisi
划重点,错误的最后说到:期待一个匹配的bean但是发现了2个(expected single matching bean but found 2:zhangsan lisi)
出现错误的原因在于@Autowired按照byType注入,当配置文件中出现多个Person对象的时候就不知道该注入哪一个了!
那么解决方式就是@Autowired结合@Qualifier使用
@Qualifier是byName注入
如果@Autowired并且有
@Qualifier("zhangsan")
也就是说按照byType的对象名为zhangsan的Person对象注入,于是乎:问题解决。
代码改动如下:
运行结果:
Person:class scuec.test.spring.bean.Person,Name:张三,Age:20
scuec.test.spring.bean.Customer@1a1d6a08
小结:
我们重在演示@Autowired以及@Qualifier。选的是注入属性,实际建议按照注入setter方法注入。