具有多个数据源的 Spring Boot + JNDI [英] Spring Boot with multiple datasources + JNDI

查看:62
本文介绍了具有多个数据源的 Spring Boot + JNDI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I trying to create a Spring Boot app, which connects with two datasources. I am able to achieve this by following Spring Documentation,but the challenge I am facing is to achieve the following

  • 使用 Spring Boot DataSourceAutoConfiguration 通过 JNDI 查找和指定数据源属性创建数据源
  • 基于主动弹簧轮廓在上述两种方法之间切换.

我的 application.yml 看起来像

My application.yml looks like

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类如下:

JpaConfig classes for two datasources are as follows:

            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);
                }
            }

我的 Spring Boot Launch Class 如下:

My Spring Boot Launch Class is as follows:

            /*
             * 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 看起来像

and finally my pom.xml is looks like

                <?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 方法时,出现以下错误

Now when i run the main method in Application.java i get following error

            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 相关联,因此无法确定数据库类型.

I understand the reason for the error , which is while injecting DataSource in below method Spring is not able to associate properties with prefix spring.datasource.one and hence is not able to determine the datbase type.

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

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

Is there any way to achieve this using Spring Boot goodness of AutoConfiguration ,or I have to create different DataSource beans based on profiles.

推荐答案

您可以编辑包含内容的文件 JpaConfigOne.java:

You can edit file JpaConfigOne.java with content:

@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 文件:

And edit JpaConfigTwo.java file :

@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名称唯一

And Your code have two @Bean(name = "transactionManager") the same name. You must to change bean name. To make sure bean name is unique

这篇关于具有多个数据源的 Spring Boot + JNDI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆