我正在使用动态多租户创建应用程序。主数据库包含与租户连接的表格' DBS。
Everithing看起来不错。但春季启动应用程序失败的原因是:
***************************
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
我将一个bean标记为主要bean,但这没有帮助:
@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;
}
}
租户配置:
@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;
}
当忽略@Primary时,它看起来像WebMvcAutoConfiguration $ EnableWebMvcConfiguration中的错误
答案 0 :(得分:2)
分辨率很简单。我用@Primary注释标记了masterTransactionManager,但没有标记masterEntityManagerFactory bean。