具有多个数据源+ JNDI的Spring Boot

时间:2016-05-02 19:53:27

标签: java spring spring-boot

我尝试创建一个Spring Boot应用程序,它连接两个数据源。 我可以通过遵循Spring Documentation实现这一目标,但我面临的挑战是实现以下目标

  • 使用Spring Boot DataSourceAutoConfiguration通过JNDI Lookup和指定DataSource属性创建DataSource
  • 根据活动弹簧曲线在上述两种方法之间切换。

我的application.yml看起来像

server:
 port: 9001
 contextPath: /ready 
spring:
 datasource:
  one:   
   url: jdbc:mysql://localhost:3307/dummy
   driver-class-name: com.mysql.jdbc.Driver
   username: root
   password: root  
  two: 
   url: jdbc:mysql://localhost:3307/dummy_two
   driver-class-name: com.mysql.jdbc.Driver
   username: root
   password: root

---
spring:
 profiles: DEV
spring.datasource:
 one:
  jndi-name: jdbc/myDBOne
 two:
  jndi-name: jdbc/myDBTwo

两个数据源的JpaConfig类如下:

            package com.springboot.web.config;

            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.autoconfigure.jdbc.DataSourceBuilder;
            import org.springframework.boot.context.properties.ConfigurationProperties;
            import org.springframework.boot.context.properties.EnableConfigurationProperties;
            import org.springframework.context.annotation.Bean;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.context.annotation.Primary;
            import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
            import org.springframework.orm.jpa.JpaTransactionManager;
            import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
            import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
            import org.springframework.transaction.PlatformTransactionManager;
            import org.springframework.transaction.annotation.EnableTransactionManagement;

            /**
             *
             * @author amardeep2551
             */
            @Configuration

            @EnableTransactionManagement
            @EnableJpaRepositories(
                  entityManagerFactoryRef = "entityManagerFactoryOne", 
                basePackages = { "com.springboot.web.repo.one" })
            public class JpaConfigOne {





                @Primary
                @Bean(name = "entityManagerFactoryOne")
                @ConfigurationProperties(prefix = "spring.datasource.one")
                public LocalContainerEntityManagerFactoryBean entityManagerFactoryOne(
                    DataSource dataSource
                     ) {

                   LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
                lef.setPackagesToScan("com.springboot.web.domain.one");
                lef.setDataSource(dataSource);
                lef.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

                return lef;
                }

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

            /*
             * To change this license header, choose License Headers in Project Properties.
             * To change this template file, choose Tools | Templates
             * and open the template in the editor.
             */
            package com.springboot.web.config;

            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.autoconfigure.jdbc.DataSourceBuilder;
            import org.springframework.boot.context.properties.ConfigurationProperties;
            import org.springframework.context.annotation.Bean;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.context.annotation.Primary;
            import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
            import org.springframework.orm.jpa.JpaTransactionManager;
            import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
            import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
            import org.springframework.transaction.PlatformTransactionManager;
            import org.springframework.transaction.annotation.EnableTransactionManagement;

            /**
             *
             * @author amardeep2551
             */
            @Configuration
            @EnableTransactionManagement
            @EnableJpaRepositories(
                  entityManagerFactoryRef = "entityManagerFactoryTwo", 
                basePackages = { "com.springboot.web.repo.two" })
            public class JpaConfigTwo {



                @Bean(name = "entityManagerFactoryTwo")
                @ConfigurationProperties(prefix = "spring.datasource.two")
                public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                    DataSource dataSource
                     ) {

                   LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
                lef.setPackagesToScan("com.springboot.web.domain.two");
                lef.setDataSource(dataSource);
                lef.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

                return lef;
                }

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

My Spring Boot Launch Class如下:

            /*
             * To change this license header, choose License Headers in Project Properties.
             * To change this template file, choose Tools | Templates
             * and open the template in the editor.
             */
            package com.springboot.web;

            import org.springframework.boot.SpringApplication;
            import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
            import org.springframework.boot.autoconfigure.SpringBootApplication;
            import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
            import org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration;
            import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
            import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
            import org.springframework.boot.context.web.SpringBootServletInitializer;

            /**
             *
             * @author amardeep2551
             */
            @EnableAutoConfiguration
            @SpringBootApplication()
            public class Application extends SpringBootServletInitializer{
                public static void main(String[] args) {

                SpringApplication.run(Application.class, args);
                }
            }

最后我的pom.xml看起来像

                <?xml version="1.0" encoding="UTF-8"?>
            <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
                <modelVersion>4.0.0</modelVersion>
                <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>1.3.1.RELEASE</version>
                <relativePath /> <!-- lookup parent from repository -->
                </parent>

                <groupId>com.springboot.web</groupId>
                <artifactId>SpringBootWeb</artifactId>
                <version>1.0-SNAPSHOT</version>
                <packaging>war</packaging>

                <name>SpringBootWeb</name>

                <properties>
                <java.version>1.8</java.version>
                <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                </properties>

                <dependencies>


                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-data-jpa</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <version>1.14.4</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                </dependency>
                <dependency>
                    <groupId>javax</groupId>
                    <artifactId>javaee-web-api</artifactId>
                    <version>6.0</version>
                    <scope>provided</scope>
                </dependency>
                </dependencies>

                <build>
                <resources>
                    <resource>
                    <directory>src/main/resources</directory>
                    </resource>
                </resources>
                <plugins>

                    <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                        <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                        </compilerArguments>
                    </configuration>
                    </plugin>
                    <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.1.1</version>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                    </plugin>
                    <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>2.1</version>
                    <executions>
                        <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                            <artifactItem>
                                <groupId>javax</groupId>
                                <artifactId>javaee-endorsed-api</artifactId>
                                <version>6.0</version>
                                <type>jar</type>
                            </artifactItem>
                            </artifactItems>
                        </configuration>
                        </execution>
                    </executions>
                    </plugin>

                </plugins>
                </build>
            <repositories>

                <repository>
                <id>projectlombok.org</id>
                <name>Lombok Repository</name>
                <url>http://projectlombok.org/mavenrepo</url>
                </repository>
            </repositories>
            </project>

现在,当我在Application.java中运行main方法时,我得到以下错误

            org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryOne' defined in class path resource [com/springboot/web/config/JpaConfigOne.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.sql.DataSource]: : Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
                at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:464) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:829) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
                at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
                at com.springboot.web.Application.main(Application.java:26) [classes/:na]

我理解错误的原因,即在下面的方法中注入DataSource时Spring无法将属性与spring.datasource.one前缀相关联,因此无法确定数据库类型。

@Primary
@Bean(name = "entityManagerFactoryOne")
@ConfigurationProperties(prefix = "spring.datasource.one")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryOne(
        DataSource dataSource
         ) {

有没有办法使用Spring Boot配置的Spring Boot实现这一点,或者我必须根据配置文件创建不同的DataSource bean。

2 个答案:

答案 0 :(得分:0)

在我的例子中,使用application.properties文件进行配置。

datasource.one.url=jdbc:mysql://localhost:3306/demo_one
datasource.one.username=root
datasource.one.password=root
datasource.one.driver-class-name=com.mysql.jdbc.Driver

datasource.two.url=jdbc:mysql://localhost:3306/demo_two
datasource.two.username=root
datasource.two.password=root
datasource.two.driver-class-name=com.mysql.jdbc.Driver

然后相应地为JPA Configuration类中的每个datasource使用前缀。不确定基于yml文件的配置。

答案 1 :(得分:0)

您可以编辑文件JpaConfigOne.java,内容如下:

@Bean(name = "oneDataSource")
@ConfigurationProperties(prefix = "spring.datasource.one")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}


@Primary
@Bean(name = "entityManagerFactoryOne")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryOne(@Qualifier("oneDataSource") DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
    lef.setPackagesToScan("com.springboot.web.domain.one");
    lef.setDataSource(dataSource);
    lef.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    return lef;
}

并编辑JpaConfigTwo.java文件:

@Bean(name = "twoDataSource")
@ConfigurationProperties(prefix = "spring.datasource.two")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}


@Primary
@Bean(name = "entityManagerFactoryTwo")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("twoDataSource") DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
    lef.setPackagesToScan("com.springboot.web.domain.two");
    lef.setDataSource(dataSource);
    lef.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    return lef;
}

并且您的代码具有两个相同名称的@Bean(name =“ transactionManager”)。您必须更改bean名称。确保bean名称唯一