当有两个用@Qualifier 定义的候选项时,Spring 如何决定注入哪个bean?

How does Spring decide which bean to inject when there is two candidates defined with @Qualifier?

假设我有两个这样定义的bean:

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

当我在不提供@Qualifier 的情况下自动装配restTemplate 时,将注入哪个bean?怎么决定的?

@Service
public class someClass {

    @Autowired
    private RestTemplate restTemplate;

} 

注意:我测试的时候注入了其中一个bean。它没有导致任何异常。

注2:我知道我可以使用@Qualifier 来注入我想要的bean,或者我可以使用@Primary 来避免歧义。但是我只是想明白为什么它对Spring有效。

注3:当我将classConfigurationB中的方法名改成restTemplateB时,注入了ConfigurationA中定义的bean。同样,它没有导致任何异常。

我在 Spring 引导版本 1.4.4

中试过这个

实际上,您不能同时拥有这两种配置 class,因为这样会导致 bean 名称冲突。要解决此问题,请重命名方法名称:

@Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplateB() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }

这样,将创建两个RestTemplate,分别使用restTemplaterestTemplateB名称,第一个将在服务class中注入。

我想你会发现,如果你 运行 你的应用程序,它会记录一个错误,如 requried a single bean but 2 were found

然而,您可以做的是使用 @Qualifier 在您需要注入并命名您的 bean 定义的地方消除歧义,即对于您的示例。

@Configuration
public class Configuration {

    @Bean(name="restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }

    @Bean(name="restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

然后当你开始注入和使用模板时

@Service
public class someClass {

    @Autowired
    @Qualifer("restTemplateA")
    private RestTemplate restTemplate;

} 

但是,您也可以使用 @Primary 将其中一个模板标记为主要模板,然后该 bean 将在您不符合自动装配条件的每个地方使用。

    @Bean(name="restTemplateA")
    @Primary
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }

案例 1: 配置中的相同方法(bean)名称 类。

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

结果:注入ConfigrationB中的restTemplate。 ConfigurationA 中的 restTemplate 被 ConfigurationB 中的 restTemplate 覆盖,如日志中所示:

o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'restTemplate' with a different definition: replacing ...

重要说明:从 spring 引导版本 2.1 开始,Bean 覆盖默认禁用(您可以查看此 link

案例2:将ConfigurationB中的方法名更改为restTemplateB。

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplateB() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

结果: ConfigurationA 和 ConfigurationB 中的两个 bean 都已创建。 ConfigurationA 中的 Bean 被注入。因为如果按类型自动装配找不到单个匹配的 bean,将使用 bean 名称。检查 了解更多信息