簡體   English   中英

Spring Boot ConflictingBeanDefinitionException:@Controller 的注釋指定的 bean 名稱 class

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

我的 Spring 引導應用程序中不斷出現ConflictingBeanDefinitionException錯誤。 我不完全確定如何解決它,我有幾個@Configuration注釋類幫助設置 Thymeleaf、Spring 安全和 Web。為什么應用程序嘗試設置homeController兩次? (它在哪里嘗試這樣做?)

錯誤是:

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]

我的 spring 引導主應用程序初始化程序:

@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);
    }

}

我的數據庫配置文件:

@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();
  }

}

我的 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;
}

}

我的 Web 配置 class:

@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();
    }
}

我的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";
    }
}

什么可能導致我的 controller class 出現ConflictingBeanDefinitionException錯誤?

我遇到了同樣的問題,但出於不同的原因。

如果您在項目中移動類並且未能進行“清理”,也會發生這種情況。

我將 gradle 與 spring-boot 插件一起使用。 現在我通常運行:

$> ./gradlew clean bootRun

當我使用 InteliJ 運行Spring 集成測試時,我遇到了同樣的問題。

重構后,我的一個控制器類實際上在/out/production/classes目錄中重復,這是自 2017.2 版以來 Intelij 的默認輸出目錄。 由於 gradle 輸出目錄不同(它是build/classes ),gradle clean 目標沒有效果。

對我來說,解決方案是手動刪除/out/production/classes並重新運行我的集成測試。

有關沒有 2 個輸出目錄的可能持久解決方案,請參見此處

正如我發現的,解決方案是通過在組件掃描中包含一個過濾器來禁用雙重初始化。 就我而言:

@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);
    }
}

在更改了幾個文件夾名稱和相關包名稱后,我在 mvn 中遇到了這個問題。 比我應用 maven clean 並再次運行 spring boot,都解決了:

mvn clean
mvn spring-boot:run

似乎您有兩個 entityManagerFactory,一個您將自動裝配,另一個您以編程方式解析為 Bean:

@Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;

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

我認為您只需要在 entityManagerFactory() 方法中配置工廠。

我在使用 spring-boot 生成的 .war 文件時遇到了同樣的問題。 批准的解決方案(Timothy Tuti 自己的解決方案)對我來說並不完全適用,但我稍微調整了一下,它起作用了。 我剛剛在我的 Application.java 中添加了以下行:

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

作為參考,這是我完整的 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);
    }

}

我通過在 class 之上添加一個 bean 名稱解決了我的問題。

@Component("myBeanName1")
public class MyBean {

}

並以這種方式使用@Autowire初始化它:

@Autowire
@Qualifier("myBeanName1")
MyBean myBean;

讓我們假設您的 package 名稱 - com.example.company和 class 名稱是RestExceptionHandler 然后你需要添加與 package 相同的全名。

添加注解@Component("com.example.company.RestExceptionHandler")

它將識別您的 class 而不會發生沖突。

當當前模塊(比如 X)的一個依賴項(比如模塊 Y)也定義了相同的 class 時,我遇到了同樣的問題。所以我不得不創建一個單獨的模塊(比如 Z)來存儲公共類,然后添加對 Z 的依賴供 X 和 Y 使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM