Spring boot Multi-module project multi-datasource

2.9k views Asked by At

I'm trying to develop a multi-module spring boot project with multi-datasource connection. I have separate this project in 5 modules: -springboot-multiple-maven-modules: 1. domain -> database2's model 2. domain2 -> database2's model 3. persistence -> database1's persistence 4. persistence2 -> database2's persistence 5. web -> Access to database1 and database2

You can download the code in the following link: GitHub Project

I've configure both datasource in this way: - database1:

package rc.persistence;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "hotelEntityManagerFactory", transactionManagerRef = "hotelTransactionManager", basePackages = {
        "rc.repository" }) //Mirar si se puede sustituir por rc.domain o rc.repository
public class HotelDbConfig {

    @Autowired
    private Environment env;

    @Bean(name = "hotelDataSource")
    @ConfigurationProperties(prefix = "hoteles.datasource")
    public DataSource customDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("hoteles.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("hoteles.datasource.url"));
        dataSource.setUsername(env.getProperty("hoteles.datasource.username"));
        dataSource.setPassword(env.getProperty("hoteles.datasource.password"));
        return dataSource;
    }

    @Bean(name = "hotelEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("hotelDataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("rc.domain")
                .persistenceUnit("hotel").build();
    }

    @Bean(name = "hotelTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("hotelEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
  • database2:
package rc.persistence2;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "cocheEntityManagerFactory", transactionManagerRef = "cocheTransactionManager", basePackages = {
        "rc.repository2" }) 

public class CocheDbConfig {

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "cocheDataSource")
    @ConfigurationProperties(prefix = "coches.datasource")
    public DataSource customDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("coches.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("coches.datasource.url"));
        dataSource.setUsername(env.getProperty("coches.datasource.username"));
        dataSource.setPassword(env.getProperty("coches.datasource.password"));
        return dataSource;
    }

    @Primary
    @Bean(name = "cocheEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("cocheDataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("rc.domain2")
                .persistenceUnit("coche").build();
    }

    @Primary
    @Bean(name = "cocheTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("cocheEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

But when I try to use repositories from web module:

package rc.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import rc.domain2.Coche;
import rc.persistence2.CocheRepository;

@RestController
public class CocheController {

    @Autowired
    private CocheRepository cocheRepository;

    public CocheController(CocheRepository cocheRepository) {
        this.cocheRepository = cocheRepository;
    }

    @GetMapping(value = "/coches")
    public List<Coche> getCoches() {
        List<Coche> hotels = this.cocheRepository.findAll();
        return hotels;
    }
}

It shows me the following error:

I've tried differents possibilities but always the same result:

2018-09-27 17:08:58.399 WARN 15272 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cocheController' defined in file [C:\springboot-multiple-maven-modules\web\target\classes\rc\web\CocheController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'rc.persistence2.CocheRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} 2018-09-27 17:08:58.399 INFO 15272 --- [
main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'coche' 2018-09-27 17:08:58.400 INFO 15272 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'hotel' 2018-09-27 17:08:58.403 INFO 15272 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2018-09-27 17:08:58.421 INFO 15272 --- [ main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2018-09-27 17:08:58.670 ERROR 15272 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :

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


Description:

Parameter 0 of constructor in rc.web.CocheController required a bean of type 'rc.persistence2.CocheRepository' that could not be found.

Action:

Consider defining a bean of type 'rc.persistence2.CocheRepository' in your configuration.

Please help!!

Thanks in advance!

1

There are 1 answers

0
David Pham On BEST ANSWER

You got a error in the datasource configuration. Your CocheDbConfig datasource is scanning in the based packages "rc.repository2" to find out Repository class so it can't find the bean 'rc.persistence2.CocheRepository' in your controller.

You should change the based packages in your database2 datasource like this

@EnableJpaRepositories(entityManagerFactoryRef = "cocheEntityManagerFactory", transactionManagerRef = "cocheTransactionManager", basePackages = {
        "rc.persistence2" })