Аннотация ресурса: не определяется квалификационный bean типа [javax.sql.DataSource]: ожидаемое одиночное соответствие bean, но найдено 2
Я использую конфигурацию на основе Java Spring для настройки нескольких баз данных с данными Spring.
В файле конфигурации я создаю два data source
для MySQL
и MSSQL-Server
. При попытке ввести зависимость с менеджером сущности с помощью аннотации @Resource
я получаю следующее исключение:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: mysql_datasource,secure_datasource
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1016)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:815)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:743)
Ниже приведен мой код:
@Bean(name="secure_datasource")
public DataSource dataSource(){
try{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(environment.getProperty("sc.db.url"));
dataSource.setDriverClass(environment.getProperty("sc.db.driver.class"));
dataSource.setUser(environment.getProperty("sc.db.username"));
dataSource.setPassword(environment.getProperty("sc.db.password"));
dataSource.setIdleConnectionTestPeriod(60);
dataSource.setMaxPoolSize(10);
dataSource.setMaxStatements(7);
dataSource.setMinPoolSize(1);
return dataSource;
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
.................
@Bean(name="mysql_datasource")
public DataSource dataSource(){
try{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(environment.getProperty("db.url"));
dataSource.setDriverClass(environment.getProperty("db.driver.class"));
dataSource.setUser(environment.getProperty("db.username"));
dataSource.setPassword(environment.getProperty("db.password"));
dataSource.setIdleConnectionTestPeriod(60);
dataSource.setMaxPoolSize(100);
dataSource.setMaxStatements(50);
dataSource.setMinPoolSize(10);
return dataSource;
}catch(Exception ex){
throw new RuntimeException(ex);
}
}
.......
@Resource(value="mysql_datasource")
@Bean(name="entity_manager_factory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factoryBean.setPackagesToScan(environment.getProperty("package.scan"));
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
return factoryBean;
}
Я также пытаюсь использовать аннотацию @Qualifier
, предлагая эту ссылку, но все же получаю ошибку. Используя 2 beans того же типа: javax.sql.DataSource в Spring
Ответы
Ответ 1
У меня была такая же проблема, и после большой головной боли я наткнулся на этот doc, который заставил меня чувствовать себя действительно немым: (
Все, что вам нужно, это @Primary на одном из ваших DataSources и Spring -Boot больше не будет запутаться... Вот одна из моих конфигураций... Остальные в значительной степени идентичны, указывая на другие БД и без @Primary на них...
@Configuration
@EnableTransactionManagement
@EntityScan(basePackages = {"somepackage.entities"})
@EnableJpaRepositories(entityManagerFactoryRef = "emfDB1", transactionManagerRef = "tmDB1", basePackages = {"somepackage.repositories"})
class PersistenceDB1 {
@Bean
@Primary
DataSource dsDB1() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://someserver:3306/proativo");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
@Bean
@Primary
LocalContainerEntityManagerFactoryBean emfDB1() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dsDB1());
entityManagerFactoryBean.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
entityManagerFactoryBean.setPersistenceXmlLocation("classpath:META-INF/DB1-persistence.xml");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", "SEVERE"); // SEVERE / FINEST
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
@Bean
@Primary
JpaTransactionManager tmDB1() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emfDB1().getNativeEntityManagerFactory());
return transactionManager;
}
}
Изменить:
Забыл упомянуть: Вероятно, из-за того, как мои классы конфигурации выполнены, метод исключения некоторых классов в @EnableAutoConfiguration не работал у меня...
Ответ 2
У меня была такая же проблема, и я нашел это старое сообщение, которое объясняло это:
http://xantorohara.blogspot.ch/2013/11/spring-boot-jdbc-with-multiple.html
Похоже, что если вам нужны несколько источников данных, магия загрузки Spring заканчивается, и вам нужно взять ее вручную.
В моем случае мне пришлось модифицировать EnableAutoConfiguration, чтобы самостоятельно использовать конфигурацию источника данных и менеджера транзакций:
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
Похоже, что волшебство загрузки Spring закончилось в тот момент, когда мне пришлось использовать несколько источников данных...
Ответ 3
В моем случае конфигурация была в xml файле, поэтому мне нужно добавить первичный = "true" в тег bean одного из определенных источников данных.