使用相同的方法名称为不同的配置文件定义Spring Bean

时间:2019-12-19 09:39:27

标签: java spring

我有一个配置类,它根据选定的概要文件定义了两个bean,其中包含重写的配置方法:

@Configuration
class MyConfig {
    @Profile("profile")
    @Bean
    MyBean myBean(MyBeanProperties properties) {
        return new MyBean(properties);
    }

    @Profile("!profile")
    @Bean
    MyBean myBean(MyBeanProperties properties, AdditionalProperties addProps) {
        MyBean result = new MyBean(properties);
        result.addAdditionalProperties(addProps);
        return result;
    }
}

和一个将MyBean自动连接到其中的类

@Service
class MyService {
     MyBean autowiredBean;
     private MyService(MyBean bean) { this.autowiredBean = bean; }
}

现在,当我启动Spring上下文时,它失败并显示消息

  

com.example.MyServce中的构造函数的参数0需要一个类型为'com.example.MyBean'的bean。

那怎么可能?我清楚地定义了Spring bean,以便在创建上下文时将其显示。

3 个答案:

答案 0 :(得分:1)

这是由于两个 bean 定义了相同的方法名称,并且根据某些条件(在这种情况下基于配置文件)预计将跳过其中一个 bean 时引起的。在这种情况下,“myBean”用不同的配置文件定义了两次。

解析配置类的方式是遍历该类中的所有 beanMethods 并添加相应的 bean 定义。迭代是按照 beanMethods 在 config 类中定义的顺序进行的。 Here 是代码的链接。

根据这些 bean 在 config 类中定义的顺序,如果根据配置文件注释预期跳过定义的第一个 bean,则 beanMethod 名称将添加到“to-be-skiipped”列表中豆方法。 Here 是代码的链接。

现在,当它遇到同名的第二个 bean 时,它看到这个 beanMethod 名称已经存在于“要跳过的”方法列表中,因此即使没有固有条件(例如配置文件),这将导致它被跳过。 Here 是代码的链接。

您会注意到,如果您交换 bean 的顺序并使用之前失败的相同配置文件来运行,那么 bean 将被拾取。

在配置类中使用唯一的 beanMethod 名称将是避免这种情况的最佳方法。

答案 1 :(得分:0)

这样做的原因是,由于配置方法的名称,Spring认为这些Bean具有相同的名称,因此它无法实例化它们(尽管在任何给定的活动Profile中仅应创建一个)。可以正常工作:

@Configuration
class MyConfig {
    @Profile("profile")
    @Bean
    MyBean myBean(MyBeanProperties properties) {
        return new MyBean(properties);
    }

    @Profile("!profile")
    @Bean
    // note different method name
    MyBean otherBean(MyBeanProperties properties, AdditionalProperties addProps) {
        MyBean result = new MyBean(properties);
        result.addAdditionalProperties(addProps);
        return result;
    }
}

我在任何地方都没有找到这种行为的解释,所以我发布了这个自我回答的问题以供分享。

在我的现实生活中,发生了WebClient实例化,该实例在一个配置文件中用一个客户注册实例化,而在另一个配置文件中却没有一个(因为创建交换过滤器不需要)。 >

答案 2 :(得分:0)

我发现了为什么更改方法名称允许应用程序上下文加载:

问题是,spring容器要求所有的bean都具有此处https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-beanname所描述的唯一名称

每个bean具有一个或多个标识符。这些标识符在承载Bean的容器内必须是唯一的。

当不使用XML配置时,我认为具有相同bean方法名称的唯一方法是为@Bean(NAME)批注中的bean提供唯一的名称,有关详细信息,Spring bean with same method name but different qualifier fail to load