2016-12-07 2 views
1

Je crée une application avec multitenancy dynamique. La base de données master contient une table avec des connexions aux dbs des locataires.

Everithing semble ok. Mais l'application de démarrage de printemps échoue en raison de:

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

Description: 

Method requestMappingHandlerMapping in org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration required a single bean, but 2 were found: 
    - masterEntityManagerFactory: defined by method 'masterEntityManagerFactory' in class path resource [com/dimanex/api/config/MasterDatabaseConfig.class] 
    - tenantEntityManagerFactory: defined by method 'tenantEntityManagerFactory' in class path resource [com/dimanex/api/config/TenantsDatabaseConfig.class] 


Action: 

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed 


Process finished with exit code 1 

j'ai marqué un haricot comme primaire, mais cela n'a pas aidé:

@Configuration 
@EnableConfigurationProperties(JpaProperties.class) 
@EnableJpaRepositories(
    entityManagerFactoryRef = MasterDatabaseConfig.MASTER_ENTITY_MANAGER_FACTORY_NAME, 
    transactionManagerRef = MasterDatabaseConfig.MASTER_TRANSACTION_MANAGER_NAME, 
    basePackages = {"com.dimanex.api.repository.master"}) 
@EnableTransactionManagement 
public class MasterDatabaseConfig { 

    public static final String MASTER_ENTITY_MANAGER_FACTORY_NAME = "masterEntityManagerFactory"; 
    public static final String MASTER_TRANSACTION_MANAGER_NAME = "masterTransactionManager"; 

    @Bean(destroyMethod = "close") 
    public DataSource masterDataSource(@Value("${spring.datasource.url}") String url, 
             @Value("${spring.datasource.dataSourceClassName}") String dataSourceClassName, 
             @Value("${spring.datasource.username}") String user, 
             @Value("${spring.datasource.password}") String password) { 

     log.debug("Configuring datasource {} {} {}", dataSourceClassName, url, user); 
     HikariConfig config = new HikariConfig(); 
     config.setDataSourceClassName(dataSourceClassName); 
     config.addDataSourceProperty("url", url); 
     config.addDataSourceProperty("user", user); 
     config.addDataSourceProperty("password", password); 
     return new HikariDataSource(config); 
    } 

    @Bean(name = MASTER_ENTITY_MANAGER_FACTORY_NAME) 
    public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory(DataSource masterDataSource, 
                      JpaProperties jpaProperties) { 
     JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
     LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 
     em.setDataSource(masterDataSource); 
     em.setPackagesToScan(new String[]{MasterBaseObject.class.getPackage().getName()}); 
     em.setJpaVendorAdapter(vendorAdapter); 

     em.setJpaProperties(new Properties(){{ 
      final Properties self = this; 
      jpaProperties.getHibernateProperties(masterDataSource).forEach((k, v) -> self.setProperty(k, v)); 
     }}); 

     em.setPersistenceUnitName("master"); 

     return em; 
    } 

    @Bean(name = MASTER_TRANSACTION_MANAGER_NAME) 
    @Primary 
    public JpaTransactionManager masterTransactionManager(@Qualifier(MASTER_ENTITY_MANAGER_FACTORY_NAME) EntityManagerFactory masterEntityManagerFactory){ 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(masterEntityManagerFactory); 
     return transactionManager; 
    } 

} 

et locataires configs:

@Configuration 
@EnableConfigurationProperties(JpaProperties.class) 
@EnableJpaRepositories(
    entityManagerFactoryRef = TenantsDatabaseConfig.TENANT_ENTITY_MANAGER_FACTORY_NAME, 
    transactionManagerRef = TenantsDatabaseConfig.TENANT_TRANSACTION_MANAGER_NAME, 
    basePackages = {"com.dimanex.api.repository.tenant"}) 
@EnableTransactionManagement 
public class TenantsDatabaseConfig { 

    public static final String TENANT_ENTITY_MANAGER_FACTORY_NAME = "tenantEntityManagerFactory"; 
    public static final String TENANT_TRANSACTION_MANAGER_NAME = "tenantsTransactionManager"; 

    @Bean 
    public JpaVendorAdapter jpaVendorAdapter() { 
     return new HibernateJpaVendorAdapter(); 
    } 

    @Bean 
    public MultiTenantConnectionProvider multiTenantConnectionProvider(@Value("${spring.datasource.dataSourceClassName}") String dataSourceClassName) { 
     return new DimanexMultiTenantConnectionProvider(dataSourceClassName); 
    } 

    @Bean 
    public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() { 
     return new DimanexCurrentTenantResolver(); 
    } 

    @Bean(name = TENANT_ENTITY_MANAGER_FACTORY_NAME) 
    public LocalContainerEntityManagerFactoryBean tenantEntityManagerFactory(@Value("${spring.jpa.properties.hibernate.dialect}") String hibernateDialect, 
                      DataSource masterDataSource, 
                      MultiTenantConnectionProvider connectionProvider, 
                      CurrentTenantIdentifierResolver tenantResolver) { 

     LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean(); 
     emfBean.setPackagesToScan(TenantBaseObject.class.getPackage().getName()); 
     emfBean.setJpaVendorAdapter(jpaVendorAdapter()); 
     emfBean.setDataSource(masterDataSource); 
     Map<String, Object> properties = new HashMap<>(); 
     properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE); 
     properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider); 
     properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver); 

     properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy"); 
     properties.put("hibernate.dialect", hibernateDialect); 

     emfBean.setJpaPropertyMap(properties); 

     return emfBean; 
    } 

    @Bean(name = TENANT_TRANSACTION_MANAGER_NAME) 
    public JpaTransactionManager tenantsTransactionManager(@Qualifier(TENANT_ENTITY_MANAGER_FACTORY_NAME) EntityManagerFactory tenantEntityManager) { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(tenantEntityManager); 
     return transactionManager; 
    } 

Il ressemble bug dans WebMvcAutoConfiguration $ EnableWebMvcConfiguration lorsqu'il ignore @Primary

+0

La résolution était simple. J'ai marqué masterTransactionManager avec l'annotation @Primary mais pas le bean masterEntityManagerFactory. – coreer

Répondre

1

Résolution w aussi simple. J'ai marqué masterTransactionManager avec l'annotation @Primary mais pas le bean masterEntityManagerFactory.