Java Spring Boot ConflictingBeanDefinitionException:@Controller 类的注解指定 bean 名称

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28498295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 06:20:02  来源:igfitidea点击:

Spring Boot ConflictingBeanDefinitionException: Annotation-specified bean name for @Controller class

javaspringspring-mvcspring-securityspring-boot

提问by Timothy Tuti

I keep getting the ConflictingBeanDefinitionException error in my Spring boot application. I am not entirely sure as to how to address it, I have several @Configuration annotated classes helping to set up Thymeleaf, Spring Security and Web. Why is the application trying to setup the homeController twice? (and where is it trying to do this?)

我在 Spring 启动应用程序中不断收到 ConflictingBeanDefinitionException 错误。我不完全确定如何解决它,我有几个 @Configuration 注释类帮助设置 Thymeleaf、Spring Security 和 Web。为什么应用程序尝试设置 homeController 两次?(它在哪里试图做到这一点?)

The error is:

错误是:

org.springframework.beans.factory.BeanDefinitionStoreException: 
Failed to parse configuration class [org.kemri.wellcome.hie.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'homeController' for bean class [org.kemri.wellcome.hie.HomeController] conflicts with existing, non-compatible bean definition of same name and class [org.kemri.wellcome.hie.controller.HomeController]

My spring boot main application initializer:

我的 spring boot 主应用程序初始化程序:

@EnableScheduling
@EnableAspectJAutoProxy
@EnableCaching
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}

My database config file:

我的数据库配置文件:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="org.kemri.wellcome.hie.repositories")
@PropertySource("classpath:application.properties")
public class DatabaseConfig {

  @Autowired
  private Environment env;

  @Autowired
  private DataSource dataSource;

  @Autowired
  private LocalContainerEntityManagerFactoryBean entityManagerFactory;

   @Bean
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
    dataSource.setUrl(env.getProperty("spring.datasource.url"));
    dataSource.setUsername(env.getProperty("spring.datasource.username"));
    dataSource.setPassword(env.getProperty("spring.datasource.password"));
    return dataSource;
  }
  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean entityManagerFactory =
        new LocalContainerEntityManagerFactoryBean();

    entityManagerFactory.setDataSource(dataSource);

    // Classpath scanning of @Component, @Service, etc annotated class
    entityManagerFactory.setPackagesToScan(
        env.getProperty("spring.jpa.hibernate.entitymanager.packagesToScan"));

    // Vendor adapter
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    entityManagerFactory.setJpaVendorAdapter(vendorAdapter);

    // Hibernate properties
    Properties additionalProperties = new Properties();
    additionalProperties.put(
        "hibernate.dialect", 
        env.getProperty("spring.jpa.hibernate.dialect"));
    additionalProperties.put(
        "hibernate.showsql", 
        env.getProperty("spring.jpa.hibernate.showsql"));
    additionalProperties.put(
        "hibernate.hbm2ddl.auto", 
        env.getProperty("spring.jpa.hibernate.hbm2ddl.auto"));
    entityManagerFactory.setJpaProperties(additionalProperties);

    return entityManagerFactory;
  }
  @Bean
  public JpaTransactionManager transactionManager() {
    JpaTransactionManager transactionManager = 
        new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(
        entityManagerFactory.getObject());
    return transactionManager;
  }
  @Bean
  public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
  }

}

My Thymeleaf config file:

我的 Thymeleaf 配置文件:

@Configuration
public class ThymeleafConfig {

@Bean
public ServletContextTemplateResolver templateResolver(){
    ServletContextTemplateResolver thymeTemplateResolver = new ServletContextTemplateResolver();
    thymeTemplateResolver.setPrefix("/WEB-INF/views/");
    thymeTemplateResolver.setSuffix(".html");
    thymeTemplateResolver.setTemplateMode("HTML5");
    return thymeTemplateResolver;
}   

@Bean
public SpringSecurityDialect springSecurityDialect(){
    SpringSecurityDialect dialect = new SpringSecurityDialect();
    return dialect;
}

@Bean
public SpringTemplateEngine templateEngine() {
    SpringTemplateEngine engine = new SpringTemplateEngine();   
    engine.addTemplateResolver(templateResolver());
    Set<IDialect> dialects = new HashSet<IDialect>();
    dialects.add(springSecurityDialect());
    engine.setAdditionalDialects(dialects);     
    return engine;
}

@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
    ThymeleafViewResolver resolver = new ThymeleafViewResolver();
    resolver.setTemplateEngine(templateEngine());
    resolver.setViewClass(ThymeleafTilesView.class);
    resolver.setCharacterEncoding("UTF-8");
    return resolver;
}

}

}

My Web config class:

我的 Web 配置类:

@Configuration
@PropertySource("classpath:application.properties")
public class WebConfig extends WebMvcAutoConfigurationAdapter  {

    @Autowired
    private Environment env;

    @Bean
    public JavaMailSenderImpl javaMailSenderImpl() {
        JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl();
        mailSenderImpl.setHost(env.getProperty("smtp.host"));
        mailSenderImpl.setPort(env.getProperty("smtp.port", Integer.class));
        mailSenderImpl.setProtocol(env.getProperty("smtp.protocol"));
        mailSenderImpl.setUsername(env.getProperty("smtp.username"));
        mailSenderImpl.setPassword(env.getProperty("smtp.password"));
        Properties javaMailProps = new Properties();
        javaMailProps.put("mail.smtp.auth", true);
        javaMailProps.put("mail.smtp.starttls.enable", true);
        mailSenderImpl.setJavaMailProperties(javaMailProps);
        return mailSenderImpl;
    }

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

My controller (where there is an error setting up the controller)

我的控制器(设置控制器时出错)

@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);

        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

        String formattedDate = dateFormat.format(date);

        model.addAttribute("serverTime", formattedDate );

        return "index.html";
    }
}

What might be causing the ConflictingBeanDefinitionException error for my controller class?

什么可能导致我的控制器类出现 ConflictingBeanDefinitionException 错误?

采纳答案by Timothy Tuti

The solution, as I found out, is to disable double initialization by including a filter in the component scan. In my case:

正如我发现的,解决方案是通过在组件扫描中包含一个过滤器来禁用双重初始化。就我而言:

@EnableScheduling
@EnableAspectJAutoProxy
@EnableCaching
@Configuration
@ComponentScan(basePackages = { "org.kemri.wellcome.hie" }, 
    excludeFilters = {@Filter(value = Controller.class, type = FilterType.ANNOTATION)})
@EnableAutoConfiguration
@PropertySource("classpath:application.properties")
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

回答by sven.kwiotek

It seems you have two entityManagerFactory, one you will autowire and one you resolve programmatically as Bean:

似乎您有两个 entityManagerFactory,一个您将自动装配,另一个您以编程方式解析为 Bean:

@Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
...
}

I think you just need your configured Factory in entityManagerFactory() method.

我认为您只需要在 entityManagerFactory() 方法中配置工厂。

回答by lotif

I was having the same problem with a generated .war file from spring-boot. the approved solution (Timothy Tuti's own solution) didn't quite work for me exactly as-is, but I tweaked it a little bit and it worked. I just added the following line to my Application.java:

我在使用 spring-boot 生成的 .war 文件时遇到了同样的问题。批准的解决方案(Timothy Tuti 自己的解决方案)对我来说并不完全适用,但我稍微调整了一下,它起作用了。我刚刚在我的 Application.java 中添加了以下行:

@ComponentScan(basePackages = { "com.mypackage" })

@ComponentScan(basePackages = { "com.mypackage" })

For reference, here goes my full Application.java

作为参考,这是我完整的 Application.java

package com.inmoment.devchallenge;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;

@SpringBootApplication
@Configuration
@ComponentScan(basePackages = { "com.inmoment.devchallenge.controller" })
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

    @Configuration
    @EnableNeo4jRepositories(basePackages = "com.inmoment.devchallenge.repository")
    static class ApplicationConfig extends Neo4jConfiguration {

        public ApplicationConfig() {
            setBasePackage("com.inmoment.devchallenge.repository");
        }

        @Bean
        GraphDatabaseService graphDatabaseService() {
            return new GraphDatabaseFactory().newEmbeddedDatabase("accessingdataneo4j.db");
        }
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}

回答by mchlstckl

I ran into the same problem but for a different reason.

我遇到了同样的问题,但出于不同的原因。

This can also occur if you move your classes around in your project and fail to do a 'clean'.

如果您在项目中移动类并且未能进行“清理”,也会发生这种情况。

I use gradle with spring-boot plugin. Now I usually run:

我将 gradle 与 spring-boot 插件一起使用。现在我通常运行:

$> ./gradlew clean bootRun

回答by user3793803

I had the same problem on a Spring integration test when I ran it with InteliJ.

当我使用 InteliJ 运行Spring 集成测试时,我遇到了同样的问题。

After a refactor, one of my controller class was actually duplicate in the /out/production/classesdirectory which is the default output directory for Intelij since version 2017.2. Since the gradle output directory is different (It's build/classes), the gradle clean goal had no effect.

重构后,我的一个控制器类实际上在/out/production/classes目录中重复,这是自 2017.2 版以来 Intelij 的默认输出目录。由于 gradle 输出目录不同(它是build/classes),gradle clean 目标没有效果。

For me the solution was to manually remove /out/production/classesand re run my integration test.

对我来说,解决方案是手动删除/out/production/classes并重新运行我的集成测试。

For a possible durable solution not having 2 output directories see here

有关没有 2 个输出目录的可能持久解决方案,请参见此处

回答by tolga

I encountered this with mvn after changing several folder names and related package names. Than I applied maven clean and run spring boot again, all solved:

在更改了几个文件夹名称和相关包名称后,我在 mvn 中遇到了这个问题。比我应用 maven clean 并再次运行 spring boot,都解决了:

mvn clean
mvn spring-boot:run