在类路径资源[path]中已经定义了一个名称为该的bean,并且禁用了覆盖。

28

我有使用Transport Client和ESTemplate的Spring Data Elasticsearch的java配置。

@Configuration
@EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
@PropertySource("file:path-to-file")
public class ESConfig {

    @Bean
    ElasticsearchTemplate elasticsearchTemplate(Client client) {
        return new ElasticsearchTemplate(client);
    }

    @Bean
    Client client() { 
// configuration of the ES client
   }

}

我有一个配置文件,它在另一个项目中扩展了上述的那个。

@Configuration
@ComponentScan("package-prefix-that-matches-packages-in-both-projects")
@EnableElasticsearchRepositories(basePackages = "subpackage-in-this-project")
@PropertySource("file:same-path-to-file-as-in-the-config-above")
public class ExtendedESConfig extends ESConfig {

    @Value("index-name")
    private String indexName;

    @Bean
    public String indexName() {
        return indexName;
    }
}

执行第三个Spring Boot应用程序时,该应用程序使用项目中的ExtendedESConfig依赖项。我遇到了这个问题,但我无法理解为什么会发生这种情况。这个问题在从2.0.5.RELEASE Spring Boot版本升级到2.2.9.RELEASE后开始出现。


***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'elasticsearchTemplate', defined in class path resource [my/package/ESConfig.class], could not be registered. A bean with that name has already been defined in class path resource [my/other/package/ExtendedESConfig.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

2020-08-30 16:49:46 ERROR [main] org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter:40 - 

我的评论中有一个重要的声明:

...很遗憾,我不是写这个ES配置并构建整个基础架构的人...

在提问时,我没有拥有ExtendedESConfig也无法更改它。


两个配置类都标记了@Configuration,且一个配置类继承另一个配置类。所以父类中的所有bean将被创建两次。请从父类中删除@Configuration注解并尝试。此外,在配置类中使用继承不是一个好习惯。 - Pratapi Hemant Patel
@PratapiHemantPatel 谢谢,我知道这很糟糕,但不幸的是,我不是编写此ES配置并构建整个基础架构的人。我会尝试这个方法,但即使这有所帮助,这也会引发许多其他问题,因为带有ES配置的项目在太多地方中被作为单独使用。 - improbable
如果您拥有或可以更新ExtendedESConfig类,则可以在@ComponentScan注释上使用excludeFilter来排除ESConfig类。 - Pratapi Hemant Patel
我之前也遇到了类似的问题。在我的情况下,该类定义带有@Service注释。这实际上也使它成为了@Bean,而这与@Configuration类中的@Bean定义发生了冲突。在Spring 2.6.3中,删除@Service修饰符解决了我的问题。 - Asa
4个回答

16
您可以在application.properties中添加下一个属性:
spring.main.allow-bean-definition-overriding=true

7
您所说的是显而易见的,因为在日志中文字面上已经被表述了“考虑重命名其中一个bean或通过设置spring.main.allow-bean-definition-overriding=true启用覆盖”。除此之外,与我的情况无关。这不是一个答案。 - improbable
1
然而它确实对一些人有所帮助。 - IKo

5

在Spring Boot 2.1中,覆盖bean的默认行为已被禁用。详见Spring Boot 2.1 Release Notes

如果您不拥有或不想修改两个配置类,则可以使用@ComponentScan从您的SpringBootApplication类中排除父配置。

@SpringBootApplication
@ComponentScan(excludeFilters = 
        {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ESConfig.class)})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

我希望从父配置获取豆子,而不是被排除在外。 - improbable
1
由于子配置仍然是一个配置类,因此在父配置中定义的Bean仍将被创建。排除父级将只允许父级Bean被创建一次,而不是两次。 - Pratapi Hemant Patel
这可能对某些人有用,但这并没有回答我的问题。 - improbable

0

我在我的@Configuration类中使用自定义的springSecurityFilterChain方法时遇到了类似的问题。应用程序告诉我它无法创建名为springSecurityFilterChain的Bean,因为它已经在别处定义了(在我的情况下,在Spring Security包中,就像你的情况一样,我无法修改)。

我在这里找到了解决方案,只需要更改我的自定义方法名称即可;我选择了customFilterChain。所以它从以下内容变成了:

@Bean
public SecurityFilterChain springSecurityFilterChain(HttpSecurity http) throws Exception {
    return http
            .csrf().disable()
            // etc
}

to:

@Bean
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
    return http
            .csrf().disable()
            // etc
}

真是太神奇了,它起作用了。就像文章所说的那样,Spring默认使用方法名来构建bean。希望能有所帮助。


1
这不是一个答案。这只是一个解决问题的权宜之计,而不是你认为我不知道的解决方案。而且这个权宜之计还涉及到完全与此无关的Spring Security。 - improbable

-2
在你的模块中找到:resources/application.properties 并写入以下内容:
spring.main.allow-bean-definition-overriding=true

如果需要帮助,您需要启用Bean覆盖机制。


1
现有非答案的副本 - improbable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接