Reputation: 2661
I am developing a Spring Boot based application in which I would like to create 2 beans: One will point to 'Oracle' database; the other will point to Hive. I've declared them as follows:
public @Bean
BoneCPDataSource metadataDataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setDriverClass(getDriver());
boneCPDataSource.setJdbcUrl(getJdbcUrl());
boneCPDataSource.setUser(getUser());
boneCPDataSource.setPassword(getPassword());
boneCPDataSource.setMaxConnectionsPerPartition(5);
boneCPDataSource.setPartitionCount(5);
return boneCPDataSource;
}
public @Bean
BasicDataSource hiveDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
// Note: In a separate command window, use port forwarding like this:
//
// ssh -L 127.0.0.1:9996:<server>:<port> -l <userid> <server>
//
// and then login as the generic user.
basicDataSource.setDriverClassName("org.apache.hadoop.hive.jdbc.HiveDriver");
basicDataSource.setUrl("jdbc:hive://127.0.0.1:9996:10000/mytable");
return basicDataSource;
}
Problem is at the startup I am getting this:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private javax.sql.DataSource
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration.dataSource;
nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type [javax.sql.DataSource] is defined: expected
single matching bean but found 2: metadataDataSource,hiveDataSource
Mainly because both of them inherit from javax.sql.DataSource. What's the best way to fix this?
EDIT:
Now I've declared them as follows:
public @Bean (name="metadataDataSource")
BoneCPDataSource metadataDataSource() {
BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
boneCPDataSource.setDriverClass(getDriver());
boneCPDataSource.setJdbcUrl(getJdbcUrl());
boneCPDataSource.setUser(getUser());
boneCPDataSource.setPassword(getPassword());
boneCPDataSource.setMaxConnectionsPerPartition(5);
boneCPDataSource.setPartitionCount(5);
return boneCPDataSource;
}
public @Bean (name="hiveDataSource")
BasicDataSource hiveDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
// Note: In a separate command window, use port forwarding like this:
//
// ssh -L 127.0.0.1:9996:<server>:<port> -l <userid> <server>
//
// and then login as the generic user.
basicDataSource.setDriverClassName("org.apache.hadoop.hive.jdbc.HiveDriver");
basicDataSource.setUrl("jdbc:hive://127.0.0.1:9996:10000/mytable");
return basicDataSource;
}
And got this exception:
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private javax.sql.DataSource
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration.dataSource;
nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type [javax.sql.DataSource] is defined: expected
single matching bean but found 2: metadataDataSource,hiveDataSource
The other classes are referring to these beans as follows:
public class MetadataProcessorImpl implements MetadataProcessor {
@Autowired
@Qualifier("metadataDataSource")
BoneCPDataSource metadataDataSource;
@Controller public class HiveController {
@Autowired
@Qualifier("hiveDataSource")
BasicDataSource hiveDataSource;
Upvotes: 17
Views: 36806
Reputation: 305
I faced similar issue. Added @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
and added manual configuration. It worked!
Upvotes: 0
Reputation: 51
If you want to use two data sources at the same time and they are not primary and secondary, you should disable DataSourceAutoConfiguration
on your application annotated by @SpringBootApplication(excludes = {DataSourceAutoConfiguration.class})
.
Since the DataSourceAutoConfiguration
will init the DataSourceInitializer
class. The init method in DataSourceInitializer
class needs to get DataSource
. When there is more than one DataSource
, the system gets confused by getting which DataSource
.
@SpringBootApplication(excludes = {DataSourceAutoConfiguration.class})
means that system won't load the DataSourceAutoConfiguration.class
when run the application.
Upvotes: 5
Reputation: 211
Set one of the beam as @Primary as described in the section 67.2 Configure Two DataSources
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-two-datasources
Upvotes: 20
Reputation: 85799
Give different names to your beans when using @Bean
:
@Bean(name="bonecpDS")
public BoneCPDataSource metadataDataSource() {
//...
}
@Bean(name="hiveDS")
public BasicDataSource hiveDataSource() {
//...
}
Then, when injecting the bean, use @Qualifier
and specify the name of the bean:
@Component
public class FooComponent {
@Autowired
@Qualifier("bonecpDS")
DataSource boneCPDataSource;
}
Upvotes: 12