Spring中xml标签primary使用
1. 问题
在项目源码目录/root/liwl_dev/java/web/spring/SpringDI/src/main/java/com/liwl/dev
创建新的School实现类SchoolImpl02.java
比SchoolImpl多了一个属性id,以示区别
package com.liwl.dev;
public class SchoolImpl02 extends SchoolImpl{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "[SchoolImpl02 bean]" + ",id" + id;
}
@Override
public void destroy() throws Exception {
System.out.println("SchoolImpl02 bean 销毁");
}
}
修改LiwanLiangImpl.java
package com.liwl.dev;
public class LiwanLiangImpl implements LiwanLiang{
private String name;
private int age;
private School school;
private School school02;
private Company company;
public LiwanLiangImpl(){
System.out.println("调用LiwanLiangImpl bean 无参构造方法");
}
public LiwanLiangImpl(String name,int age,School school){
System.out.println("调用LiwanLiangImpl bean 有参构造方法");
this.name = name;
this.age = age;
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public School getSchool02() {
return school02;
}
public void setSchool02(School school02) {
this.school02 = school02;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
@Override
public String toString() {
return "[LiwanLiangImpl bean]" + ",name:" + name + ",age:" + age + ",school:" + school + ",company:" + company + ",school02:" + school02;
}
@Override
public void destroy() throws Exception {
System.out.println("LiwanLiangImpl bean 销毁");
}
}
修改spingdi.xml
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="school" class="com.liwl.dev.SchoolImpl">
<property name="name" value="jiangnan"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
</bean>
<bean id="school02" class="com.liwl.dev.SchoolImpl02">
<property name="name" value="jiangnan02"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号-02"/>
</bean>
<bean id="company" class="com.liwl.dev.CompanyImpl">
<property name="name" value="nsccwx"/>
<property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
</bean>
<bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byType">
<property name="name" value="liwl" />
<property name="age" value="30"/>
</bean>
</beans>
运行报错:
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'liwl001' defined in class path resource [springdi.xml]: Unsatisfied dependency expressed through bean property 'school'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.liwl.dev.School' available: expected single matching bean but found 2: school,school02
大概意思就是:
在LiwanLiangImpl.java里面,我们依赖了同一个School类型的属性:school和school02。但是通过xml里面的标签byType
时,加载到Spring容器里面两个School类型的bean:SchoolImpl和SchoolImpl01,所以Spring无从知道该如何自动装载bean=school还是bean=school2,因为它们都是同一个类型的。
2. 解决
上述解决就需要通过xml的标签primary
来处理
修改springdi.xml
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="school" class="com.liwl.dev.SchoolImpl" primary="true">
<property name="name" value="jiangnan"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
</bean>
<bean id="school02" class="com.liwl.dev.SchoolImpl02">
<property name="name" value="jiangnan02"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号-02"/>
</bean>
<bean id="company" class="com.liwl.dev.CompanyImpl">
<property name="name" value="nsccwx"/>
<property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
</bean>
<bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byType">
<property name="name" value="liwl" />
<property name="age" value="30"/>
</bean>
</beans>
运行结果
调用SchoolImpl bean 无参构造方法
调用SchoolImpl bean 无参构造方法
调用CompanyImpl bean 无参构造方法
调用LiwanLiangImpl bean 无参构造方法
[LiwanLiangImpl bean],name:liwl,age:30,school:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号,company:[CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号,school02:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号
LiwanLiangImpl bean 销毁
CompanyImpl bean 销毁
SchoolImpl02 bean 销毁
SchoolImpl bean 销毁
修改springdi.xml
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="school" class="com.liwl.dev.SchoolImpl">
<property name="name" value="jiangnan"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
</bean>
<bean id="school02" class="com.liwl.dev.SchoolImpl02" primary="true">
<property name="name" value="jiangnan02"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号-02"/>
<property name="id" value="02"/>
</bean>
<bean id="company" class="com.liwl.dev.CompanyImpl">
<property name="name" value="nsccwx"/>
<property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
</bean>
<bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byType">
<property name="name" value="liwl" />
<property name="age" value="30"/>
</bean>
</beans>
运行结果
调用SchoolImpl bean 无参构造方法
调用SchoolImpl bean 无参构造方法
调用CompanyImpl bean 无参构造方法
调用LiwanLiangImpl bean 无参构造方法
[LiwanLiangImpl bean],name:liwl,age:30,school:[SchoolImpl02 bean],id:2,company:[CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号,school02:[SchoolImpl02 bean],id:2
LiwanLiangImpl bean 销毁
CompanyImpl bean 销毁
SchoolImpl02 bean 销毁
SchoolImpl bean 销毁
3. 结论
对比上面的结果可以发现
LiwanLiangImpl里面注入了两个School的实现类的bean,xml文件也对应的配置了两个bean。
当通过byType标签,为bean:liwanliang自动注入时,因为Spring容器里面存在着2个SchoolImpl的bean,因此Spring无法正确通过类型为liwanliang注入。
这个时候,通过primary标签的值[true/false]来指定 有限注入哪个bean,就可以解决这个问题
当<bean id="school" class="com.liwl.dev.SchoolImpl" primary="true">
时,注入的是SchoolImpl的bean,所以结果是:
[LiwanLiangImpl bean],name:liwl,age:30,school:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号,company:[CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号,school02:[SchoolImpl bean],name:jiangnan,address:江苏省无锡市滨湖区蠡湖大道1800号
当<bean id="school02" class="com.liwl.dev.SchoolImpl02" primary="true">
时,注入的是SchoolImpl02的bean,所以结果是:
[LiwanLiangImpl bean],name:liwl,age:30,school:[SchoolImpl02 bean],id:2,company:[CompanyImpl bean],name:nsccwx,address:江苏省无锡市滨湖区吟白路1号,school02:[SchoolImpl02 bean],id:2
4. 拓展
xml配置标签primary
能够指定配置在xml里面的bean,哪些是作为优先注入的bean。primary
用在autowire=byType
时,作用很明显。
另外一个标签autowire-candidate
,这个跟autowire=byType
时有所异同。
bean的autowire-candidata
默认值为true
,所以想要优先选择某个bean,需要把另外一个bean的该标签设置为false即可
比如下面的配置,就会往LiwanLiangImpl注入school,而非shool002
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="school" class="com.liwl.dev.SchoolImpl">
<property name="name" value="jiangnan"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号"/>
</bean>
<bean id="school02" class="com.liwl.dev.SchoolImpl02" autowire-candidata="false">
<property name="name" value="jiangnan02"/>
<property name="address" value="江苏省无锡市滨湖区蠡湖大道1800号-02"/>
</bean>
<bean id="company" class="com.liwl.dev.CompanyImpl">
<property name="name" value="nsccwx"/>
<property name="address" value="江苏省无锡市滨湖区吟白路1号"/>
</bean>
<bean id="liwl001" class="com.liwl.dev.LiwanLiangImpl" depends-on="school,company" autowire="byType">
<property name="name" value="liwl" />
<property name="age" value="30"/>
</bean>
</beans>