3

I am developing a Spring Boot application that uses Spring Data JPA and will need to connect to two different databases and I've run into an issue. When the application starts up it's throwing an exception basically stating that it doesn't know which datasource to use. Here is a snippet of my configuration class. The database properties(e.g. url, username, password) are defined in the application.properties file.

@Configuration
@ComponentScan(basePackages = {"com.test"})
@EnableJpaRepositories(basePackages = {"com.test.jpa.repository"})
@EnableAutoConfiguration
@EnableTransactionManagement
public class AppConfig {

@Bean(name = "dataSource1")
DataSource dataSource1(@Value("${db1.driverClassName}") String db1DriverClassName,  @Value("${db1.url}") String db1Url, @Value("${db1.username}") String db1Username, @Value("${db1.password}") String db1Password) {
    DataSource dataSource = new DataSource();

    dataSource.setDriverClassName(db1DriverClassName);
    dataSource.setUrl(db1Url);
    dataSource.setUsername(db1Username);
    dataSource.setPassword(db1Password);

    return dataSource;
}

@Bean(name = "dataSource2")
DataSource dataSource2(@Value("${db2.driverClassName}") String db2DriverClassName, @Value("${db2.url}") String db2Url, @Value("${db2.username}") String db2Username, @Value("${db2.password}") String db2Password) {
    DataSource dataSource = new DataSource();

    dataSource.setDriverClassName(db2DriverClassName);
    dataSource.setUrl(db2Url);
    dataSource.setUsername(db2Username);
    dataSource.setPassword(db2Password);

    return dataSource;
}

@Bean(name = "jpaVendorAdapter")
HibernateJpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();

    jpaVendorAdapter.setDatabase(Database.ORACLE);
    jpaVendorAdapter.setShowSql(false);
    jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");

    return jpaVendorAdapter;
}

@Bean(name = "entityManagerFactory")
@Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource1") DataSource dataSource, HibernateJpaVendorAdapter jpaVendorAdapter) {
    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();

    entityManagerFactory.setDataSource(dataSource);
    entityManagerFactory.setPersistenceXmlLocation("classpath:persistence.xml");
    entityManagerFactory.setPersistenceUnitName("springdatajpa");
    entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);

    return entityManagerFactory;
}

@Bean(name = "transactionManager")
JpaTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());

    return transactionManager;
}

Here is the exception that is being thrown:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.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: dataSource1,dataSource2
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
at com.wth.service.logging.Application.main(Application.java:11)

I have the entityManagerFactory method annotated with the @Autowired annotation and the dataSource parameter preceded with the @Qualifier("dataSource1") annotation so this should work. I've done this before in other Spring applications and haven't had any issues. This is the first time I've come across this exception.

Does anyone have any ideas/thoughts as to what could be causing this?

Thanks, Chris

user2634876
  • 127
  • 2
  • 6
  • Try removing @EnableAutoConfiguration. It looks like you're configuring your beans yourself. The exception you're getting is in ofne of the Spring classes, doesn't look like it's in one of yours. – int21h Aug 03 '14 at 19:43

4 Answers4

3

To get this working I used the following:

@SpringBootApplication(exclude = { 
  DataSourceAutoConfiguration.class, 
  HibernateJpaAutoConfiguration.class, 
  JpaRepositoriesAutoConfiguration.class, 
  DataSourceTransactionManagerAutoConfiguration.class})
public class App...

This is equivalent to:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = { 
  DataSourceAutoConfiguration.class, 
  HibernateJpaAutoConfiguration.class,
  JpaRepositoriesAutoConfiguration.class, 
  DataSourceTransactionManagerAutoConfiguration.class})

Then I had a separate Configuration class per data source that was defined as follows:

@Configuration
@EnableJpaRepositories(
  entityManagerFactoryRef="fooEntityManagerFactory", 
  transactionManagerRef="fooTransactionManager")
public class FooConfig {

  public static final String FOO_QUALIFIER = "Foo";

  @Bean @Qualifier(FOO_QUALIFIER)
  public DataSource fooDataSource() { ... }

  @Bean @Qualifier(FOO_QUALIFIER)
  public EntityManagerFactory fooEntityManagerFactory() { ... }

  @Bean @Qualifier(FOO_QUALIFIER)
  public PlatformTransactionManager fooTransactionManager(
    @Qualifier(FOO_QUALIFIER) EntityManagerFactory emf) { ... }
}
Michał Zaborowski
  • 3,911
  • 2
  • 19
  • 39
0

You're really getting the exception in Spring's DataSourceAutoConfiguration.class. Since you're configuring datasources on your own, try removing @EnableAutoConfiguration

DataSourceAutoConfiguration looks for the type DataSource (without a qualifier)

DJo
  • 2,133
  • 4
  • 30
  • 46
int21h
  • 819
  • 7
  • 15
0

As suggested by Rafal Borowiec in response to my similar post here modify your auto configuration to exclude JPA Repository Configurations.

@EnableAutoConfiguration(exclude = JpaRepositoriesAutoConfiguration.class)
Community
  • 1
  • 1
tonym2105
  • 511
  • 1
  • 6
  • 6
0

JUST remove @EnableAutoConfiguration from your configuration!

Ștefan Teslari
  • 411
  • 4
  • 6