夯实spring(十一):autowire-candidate

上一篇文章说了,当容器中某种类型的bean存在多个的时候,此时如果我们从容器中查找这种类型的bean的时候,会报下面这个异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException

当从容器中按照类型查找一个bean对象的时候,容器中却找到了多个匹配的bean,此时spring不知道如何选择了,就会报这个异常。

这种异常主要出现在2种情况中:

1,调用getBean查找符合指定类型的bean

<T> T getBean(Class<T> requiredType) throws BeansException;

2,自动注入时方式设置为byType

public interface Service {
}
public class ServiceImpl1 implements Service {
}
public class ServiceImpl2 implements Service {
}
public class SetterBean {
    private Service service;

    public Service getService() {
        return service;
    }

    public void setService(Service service) {
        this.service = service;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
    
    <bean id="impl1" class="com.chen.chat.chen.ServiceImpl1"/>
    <bean id="impl2" class="com.chen.chat.chen.ServiceImpl2"/>
    <bean id="setterBean" class="com.chen.chat.chen.SetterBean" autowire="byType"/>
</beans>

setterBean的autowire设置的是byType,即按setter方法的参数类型自动注入,SetterBean的setService的类型是Service,而Service类有2个实现类:ServiceImpl1和ServiceImpl2,而容器容器中刚好有这2个实现类的bean:impl1和impl2,所以上面代码会报错,不知道注入的时候选择那个对象注入。我们可以通过primary属性来指定一个主要的bean,当从容器中查找的时候,如果有多个候选的bean符合查找的类型,此时容器将返回primary=”true”的bean对象。

spring还有一种方法也可以解决这个问题,可以设置某个bean是否在自动注入的时候是否为作为候选bean,通过bean元素的autowire-candidate属性类配置,如:

<bean id="impl1" class="com.chen.chat.chen.ServiceImpl1" autowire-candidate="false"/>

autowire-candidate:设置当前bean在被其他对象作为自动注入对象的时候,是否作为候选bean,默认值是true。

上面的过程:

容器在创建setterBean的时候,发现其autowire为byType,即按类型自动注入,此时会在SetterBean类中查找所有setter方法列表,其中就包含了setService方法,setService方法参数类型是Service,然后就会去容器中按照Service类型查找所有符合条件的bean列表,此时容器中会返回满足Service这种类型并且autowire-candidate=”true”的bean,bean元素的autowire-candidate的默认值是true,所以容器中符合条件的候选bean有2个:impl1和impl2,setService方法只需要一个满足条件的bean,此时会再去看这个列表中是否只有一个主要的bean(即bean元素的primary=“ture”的bean),而bean元素的primary默认值都是false,所以没有primary为true的bean,此时spring容器不知道选哪个了,此时就报错了,抛出NoUniqueBeanDefinitionException异常

上面我们把impl1的autowire-candidate改为false之后,运行看看:

public class Main  {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean.xml");
        System.out.println(context.getBean(Service.class));
    }
}
com.chen.chat.chen.ServiceImpl2@2b552920

如果我们在SetterBean修改一下:

public class SetterBean {
    private List<Service> serviceList;

    public List<Service> getServiceList() {
        return serviceList;
    }

    public void setServiceList(List<Service> serviceList) {
        this.serviceList = serviceList;
    }
    @Override
    public String toString() {
        return "SetterBean{" +
                "serviceList=" + serviceList +
                '}';
    }
}

上面的setServiceList(List serviceList)输出的是容器中的impl1,还是impl2,还是2个都有呢?

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="impl1" class="com.chen.chat.chen.ServiceImpl1" autowire-candidate="false"/>
    <bean id="impl2" class="com.chen.chat.chen.ServiceImpl2"/>

    <bean id="setterBean" class="com.chen.chat.chen.SetterBean" autowire="byType"/>
</beans>

1,当 id=“impl1” 的 autowire-candidate=“false” 时

SetterBean{serviceList=[com.chen.chat.chen.ServiceImpl2@184f6be2]}

只注入了一个

1,当 id=“impl1” 的 autowire-candidate=“true” 时

SetterBean{serviceList=[com.chen.chat.chen.ServiceImpl1@184f6be2, com.chen.chat.chen.ServiceImpl2@56aac163]}

2个都有

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值