使用 JNDI 在 Spring 引导中配置多个数据源
Configure Multiple DataSource in Spring Boot with JNDI
我想使用您的应用程序服务器内置功能管理 多个 数据源并使用 JNDI 访问它。我正在使用 Spring 引导和 Spring JPA 数据。
我可以为单个数据源配置 application.properties:
spring.datasource.jndi-name=jdbc/customers
我在 context.xml 文件中的配置如下:
<Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/customer"/>
一切正常。
但是当我无法配置两个数据源时。
我确定 context.xml 文件中的配置:
<Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/customer"/>
<Resource name="jdbc/employee" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/employee"/>
我对application.properties文件配置有疑问。
我尝试了以下选项但没有成功:
spring.datasource.jndi-name=jdbc/customers,jdbc/employee
请让我知道有关 Spring 使用 JNDI 为多个数据源启动的任何详细信息。我这几天一直在找这个配置。
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.secondary.jndi-name=jdbc/project
配置class.
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
应用程序没有启动。尽管 tomcat 服务器正在启动。日志中没有打印错误。
第三次试用:使用 JndiObjectFactoryBean
我有以下application.properties
spring.datasource.primary.expected-type=javax.sql.DataSource
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.primary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.primary.jpa.show-sql=false
spring.datasource.primary.jpa.hibernate.ddl-auto=validate
spring.datasource.secondary.jndi-name=jdbc/employee
spring.datasource.secondary.expected-type=javax.sql.DataSource
spring.datasource.secondary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.secondary.jpa.show-sql=false
spring.datasource.secondary.jpa.hibernate.ddl-auto=validate
以及下面的java配置:
@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="spring.datasource.primary")
public FactoryBean primaryDataSource() {
return new JndiObjectFactoryBean();
}
@Bean(destroyMethod="")
@ConfigurationProperties(prefix="spring.datasource.secondary")
public FactoryBean secondaryDataSource() {
return new JndiObjectFactoryBean();
}
但仍然出现错误:
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/customer] is not bound in this Context. Unable to find [jdbc].
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'secondaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/employee] is not bound in this Context. Unable to find [jdbc].
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.context.web.SpringBootServletInitializer.run(SpringBootServletInitializer.java:117)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:108)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:68)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
更新:
使用以下属性文件试用:
spring.datasource.primary.expected-type=javax.sql.DataSource
spring.datasource.primary.jndi-name=java:comp/env/jdbc/customer
spring.datasource.secondary.jndi-name=java:comp/env/jdbc/employee
spring.datasource.secondary.expected-type=javax.sql.DataSource
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=validate
它在客户模式中创建了所有表,但也未能尝试找到其他表。(来自第二个模式)
您可以为此使用普通的 JndiObjectFactoryBean
。只需将 DataSourceBuilder
替换为 JndiObjectFactoryBean
即可。
Java配置
@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public FactoryBean primaryDataSource() {
return new JndiObjectFactoryBean();
}
@Bean(destroyMethod="")
@ConfigurationProperties(prefix="datasource.secondary")
public FactoryBean secondaryDataSource() {
return new JndiObjectFactoryBean();
}
属性
datasource.primary.jndi-name=jdbc/customer
datasource.primary.expected-type=javax.sql.DataSource
datasource.secondary.jndi-name=jdbc/project
datasource.secondary.expected-type=javax.sql.DataSource
您可以使用 @ConfigurationProperties
注释设置 JndiObjectFactoryBean
的每个 属性。 (参见我添加的 expected-type
,但您也可以设置 cache
或 lookup-on-startup
等)。
注意: 在执行 JNDI 查找时将 destroyMethod
设置为 ""
否则您可能会遇到这样的情况,即当应用程序关闭时您的 JNDI资源也越来越 closed/shutdown。在共享环境中,这不是您想要的。
这是您第三次试用的解决方案,稍作修改。
考虑这个解决方案(Spring Boot 1.3.2):
application.properties 文件:
spring.datasource.primary.jndi-name=java:/comp/env/jdbc/SecurityDS
spring.datasource.primary.driver-class-name=org.postgresql.Driver
spring.datasource.secondary.jndi-name=java:/comp/env/jdbc/TmsDS
spring.datasource.secondary.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.show-sql=false
配置:
@Configuration@ EnableConfigurationProperties
public class AppConfig {
@Bean@ ConfigurationProperties(prefix = "spring.datasource.primary")
public JndiPropertyHolder primary() {
return new JndiPropertyHolder();
}
@Bean@ Primary
public DataSource primaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(primary().getJndiName());
return dataSource;
}
@Bean@ ConfigurationProperties(prefix = "spring.datasource.secondary")
public JndiPropertyHolder secondary() {
return new JndiPropertyHolder();
}
@Bean
public DataSource secondaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(secondary().getJndiName());
return dataSource;
}
private static class JndiPropertyHolder {
private String jndiName;
public String getJndiName() {
return jndiName;
}
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
}
}
然后您可以按照指南 http://docs.spring.io/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html 将您的数据源与 jpa 存储库一起使用。
它对我有用并且包含更少的代码
@Configuration
public class Config {
@Value("${spring.datasource.primary.jndi-name}")
private String primaryJndiName;
@Value("${spring.datasource.secondary.jndi-name}")
private String secondaryJndiName;
private JndiDataSourceLookup lookup = new JndiDataSourceLookup();
@Primary
@Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource primaryDs() {
return lookup.getDataSource(primaryJndiName);
}
@Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource secondaryDs() {
return lookup.getDataSource(secondaryJndiName);
}
}
我获得成功和探索更多的简洁方法
在外部 tomcat 设置许多 jndi 资源,你可以 start/stop 在 eclipse.Note - 双击 eclipse 中的 tomcat 和 select 使用工作区元数据,意味着不要将应用程序部署到 tomcat webapp 文件夹。在各自的 eclipse 服务器文件中添加 jndi 资源(context.xml - ResourceLink,server.xml - Resource,web.xml - resource-ref)。
无需在application.properties中设置spring.datasource.*。因为 jndi-contest 是一种数据源类型(即 type="javax.sql.DataSource"
)被导出到外部服务器。
在 SpringBootApplication 注释 class 中,通过 jndi 查找
从所有 jndi 资源(按照#1 设置)创建数据源 bean
@Bean(name = "abcDataSource")
public DataSource getAbcDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/abcDataSource");
return dataSource;
}
如果在你的项目中使用了spring jdbc 然后提供上面的数据源来创建一个jdbc模板bean
@Bean(name = "jdbcAbcTemplate")
public JdbcTemplate abcJdbcTemplate(@Lazy @Qualifier("abcDataSource")
DataSource refDS)
{
return new JdbcTemplate(refDS);
}
只需自动装配一个 属性 类型的 DataSource 并获取 systemout 其详细信息以探索更多内容。
虽然上面的答案很好,但我将再添加一个来说明混合使用 jndi 和完整数据连接配置时的致命陷阱。在典型的开发环境中,您可以在本地开发环境中完全限定数据库连接,然后在推送到 qa 等时使用 jndi。您的
应用程序 .properties 看起来像这样:
spring.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
spring.datasource.username=userxxyyzz
spring.datasource.password=passxxyyzz
spring.datasource.platform=mssql
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
和 application-qa.properties 像这样:
spring.datasource.jndi-name=java:jboss/datasources/dbxx
当您必须定义自己的 bean 以拥有多个数据源时,就会出现问题。如果您使用默认的 Spring 托管数据源,那么它会自动检测 jndi 与完全合格的连接和 returns 应用程序代码中不需要更改的数据源。如果您定义自己的数据源,它就不再这样做了。如果你 application.properties 像这样:
spring.custom.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
spring.custom.datasource.username=userxxyyzz
spring.custom.datasource.password=passxxyyzz
spring.custom.datasource.platform=mssql
spring.custom.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
和 application-qa.properties 像这样:
spring.custom.datasource.jndi-name=java:jboss/datasources/dbxx
使用这样的数据源 bean,如 Spring 文档 https://docs.spring.io/spring-boot/docs/2.1.11.RELEASE/reference/html/howto-data-access.html
中所建议
@Primary
@Bean(name="customDataSourcePropertiesBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSourceProperties customDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name="customDataSourceBean")
@ConfigurationProperties("spring.custom.datasource")
public HiakriDataSource customDataSource(@Qualifier("customDataSourcePropertiesBean") DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
此数据源构建器不会尝试读取 application-qa.properties 中的 jndi 配置,并自动故障返回到 application.properties 返回错误的数据库连接。解决方法相当简单——测试您所处的环境并自定义创建的数据库连接类型。调试这是一个熊,因为症状是应用程序似乎忽略了应用程序-qa.properties。我分享是为了让别人免于痛苦。将 spring.profiles.active=qa 等添加到您的属性文件中以了解您所处的环境:
@Value("${spring.profiles.active}")
String profile;
@Value("${spring.custom.jndi-name}")
String jndi;
@Primary
@Bean(name="customDataSourcePropertiesBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSourceProperties customDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name="customDataSourceBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSource customDataSource(@Qualifier("customDataSourcePropertiesBean") DataSourceProperties properties) {
if(profile.equals("localhost")) {
return DataSourceBuilder
.create()
.username(properties.getDataUsername())
.password(properties.getPassword())
.url(properties.getUrl())
.driverClassName(properties.getDriverClassName())
.build();
}else {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource(jndi);
}
}
就我而言,当我使用 Spring Boot App 启动我的应用程序时,数据库配置在应用程序-dev.properties 上读取,当我在 tomcat 上发布时,使用数据源,有必要添加一个验证来检查我的配置文件是否是 prod,在这种情况下,我进行了 jndi 查找
@Bean(name = "dsName")
@ConfigurationProperties("ds.datasource.configuration")
public DataSource dataSource(@Qualifier("dsProperties") DataSourceProperties db1DataSourceProperties)
{
if(Arrays.asList(environment.getActiveProfiles()).contains("prod"))
{
final JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("java:comp/env/jdbc/DS1");
}
else
{
return db1DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
我想使用您的应用程序服务器内置功能管理 多个 数据源并使用 JNDI 访问它。我正在使用 Spring 引导和 Spring JPA 数据。
我可以为单个数据源配置 application.properties:
spring.datasource.jndi-name=jdbc/customers
我在 context.xml 文件中的配置如下:
<Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/customer"/>
一切正常。
但是当我无法配置两个数据源时。
我确定 context.xml 文件中的配置:
<Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/customer"/>
<Resource name="jdbc/employee" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/employee"/>
我对application.properties文件配置有疑问。
我尝试了以下选项但没有成功:
spring.datasource.jndi-name=jdbc/customers,jdbc/employee
请让我知道有关 Spring 使用 JNDI 为多个数据源启动的任何详细信息。我这几天一直在找这个配置。
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.secondary.jndi-name=jdbc/project
配置class.
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
应用程序没有启动。尽管 tomcat 服务器正在启动。日志中没有打印错误。
第三次试用:使用 JndiObjectFactoryBean
我有以下application.properties
spring.datasource.primary.expected-type=javax.sql.DataSource
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.primary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.primary.jpa.show-sql=false
spring.datasource.primary.jpa.hibernate.ddl-auto=validate
spring.datasource.secondary.jndi-name=jdbc/employee
spring.datasource.secondary.expected-type=javax.sql.DataSource
spring.datasource.secondary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.secondary.jpa.show-sql=false
spring.datasource.secondary.jpa.hibernate.ddl-auto=validate
以及下面的java配置:
@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="spring.datasource.primary")
public FactoryBean primaryDataSource() {
return new JndiObjectFactoryBean();
}
@Bean(destroyMethod="")
@ConfigurationProperties(prefix="spring.datasource.secondary")
public FactoryBean secondaryDataSource() {
return new JndiObjectFactoryBean();
}
但仍然出现错误:
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/customer] is not bound in this Context. Unable to find [jdbc].
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'secondaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/employee] is not bound in this Context. Unable to find [jdbc].
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.context.web.SpringBootServletInitializer.run(SpringBootServletInitializer.java:117)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:108)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:68)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
更新: 使用以下属性文件试用:
spring.datasource.primary.expected-type=javax.sql.DataSource
spring.datasource.primary.jndi-name=java:comp/env/jdbc/customer
spring.datasource.secondary.jndi-name=java:comp/env/jdbc/employee
spring.datasource.secondary.expected-type=javax.sql.DataSource
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=validate
它在客户模式中创建了所有表,但也未能尝试找到其他表。(来自第二个模式)
您可以为此使用普通的 JndiObjectFactoryBean
。只需将 DataSourceBuilder
替换为 JndiObjectFactoryBean
即可。
Java配置
@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public FactoryBean primaryDataSource() {
return new JndiObjectFactoryBean();
}
@Bean(destroyMethod="")
@ConfigurationProperties(prefix="datasource.secondary")
public FactoryBean secondaryDataSource() {
return new JndiObjectFactoryBean();
}
属性
datasource.primary.jndi-name=jdbc/customer
datasource.primary.expected-type=javax.sql.DataSource
datasource.secondary.jndi-name=jdbc/project
datasource.secondary.expected-type=javax.sql.DataSource
您可以使用 @ConfigurationProperties
注释设置 JndiObjectFactoryBean
的每个 属性。 (参见我添加的 expected-type
,但您也可以设置 cache
或 lookup-on-startup
等)。
注意: 在执行 JNDI 查找时将 destroyMethod
设置为 ""
否则您可能会遇到这样的情况,即当应用程序关闭时您的 JNDI资源也越来越 closed/shutdown。在共享环境中,这不是您想要的。
这是您第三次试用的解决方案,稍作修改。 考虑这个解决方案(Spring Boot 1.3.2):
application.properties 文件:
spring.datasource.primary.jndi-name=java:/comp/env/jdbc/SecurityDS
spring.datasource.primary.driver-class-name=org.postgresql.Driver
spring.datasource.secondary.jndi-name=java:/comp/env/jdbc/TmsDS
spring.datasource.secondary.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.show-sql=false
配置:
@Configuration@ EnableConfigurationProperties
public class AppConfig {
@Bean@ ConfigurationProperties(prefix = "spring.datasource.primary")
public JndiPropertyHolder primary() {
return new JndiPropertyHolder();
}
@Bean@ Primary
public DataSource primaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(primary().getJndiName());
return dataSource;
}
@Bean@ ConfigurationProperties(prefix = "spring.datasource.secondary")
public JndiPropertyHolder secondary() {
return new JndiPropertyHolder();
}
@Bean
public DataSource secondaryDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(secondary().getJndiName());
return dataSource;
}
private static class JndiPropertyHolder {
private String jndiName;
public String getJndiName() {
return jndiName;
}
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
}
}
然后您可以按照指南 http://docs.spring.io/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html 将您的数据源与 jpa 存储库一起使用。
它对我有用并且包含更少的代码
@Configuration
public class Config {
@Value("${spring.datasource.primary.jndi-name}")
private String primaryJndiName;
@Value("${spring.datasource.secondary.jndi-name}")
private String secondaryJndiName;
private JndiDataSourceLookup lookup = new JndiDataSourceLookup();
@Primary
@Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource primaryDs() {
return lookup.getDataSource(primaryJndiName);
}
@Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
public DataSource secondaryDs() {
return lookup.getDataSource(secondaryJndiName);
}
}
我获得成功和探索更多的简洁方法
在外部 tomcat 设置许多 jndi 资源,你可以 start/stop 在 eclipse.Note - 双击 eclipse 中的 tomcat 和 select 使用工作区元数据,意味着不要将应用程序部署到 tomcat webapp 文件夹。在各自的 eclipse 服务器文件中添加 jndi 资源(context.xml - ResourceLink,server.xml - Resource,web.xml - resource-ref)。
无需在application.properties中设置spring.datasource.*。因为 jndi-contest 是一种数据源类型(即
type="javax.sql.DataSource"
)被导出到外部服务器。在 SpringBootApplication 注释 class 中,通过 jndi 查找
从所有 jndi 资源(按照#1 设置)创建数据源 bean@Bean(name = "abcDataSource") public DataSource getAbcDataSource() { JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/abcDataSource"); return dataSource; }
如果在你的项目中使用了spring jdbc 然后提供上面的数据源来创建一个jdbc模板bean
@Bean(name = "jdbcAbcTemplate") public JdbcTemplate abcJdbcTemplate(@Lazy @Qualifier("abcDataSource") DataSource refDS) { return new JdbcTemplate(refDS); }
只需自动装配一个 属性 类型的 DataSource 并获取 systemout 其详细信息以探索更多内容。
虽然上面的答案很好,但我将再添加一个来说明混合使用 jndi 和完整数据连接配置时的致命陷阱。在典型的开发环境中,您可以在本地开发环境中完全限定数据库连接,然后在推送到 qa 等时使用 jndi。您的 应用程序 .properties 看起来像这样:
spring.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
spring.datasource.username=userxxyyzz
spring.datasource.password=passxxyyzz
spring.datasource.platform=mssql
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
和 application-qa.properties 像这样:
spring.datasource.jndi-name=java:jboss/datasources/dbxx
当您必须定义自己的 bean 以拥有多个数据源时,就会出现问题。如果您使用默认的 Spring 托管数据源,那么它会自动检测 jndi 与完全合格的连接和 returns 应用程序代码中不需要更改的数据源。如果您定义自己的数据源,它就不再这样做了。如果你 application.properties 像这样:
spring.custom.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
spring.custom.datasource.username=userxxyyzz
spring.custom.datasource.password=passxxyyzz
spring.custom.datasource.platform=mssql
spring.custom.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
和 application-qa.properties 像这样:
spring.custom.datasource.jndi-name=java:jboss/datasources/dbxx
使用这样的数据源 bean,如 Spring 文档 https://docs.spring.io/spring-boot/docs/2.1.11.RELEASE/reference/html/howto-data-access.html
中所建议 @Primary
@Bean(name="customDataSourcePropertiesBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSourceProperties customDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name="customDataSourceBean")
@ConfigurationProperties("spring.custom.datasource")
public HiakriDataSource customDataSource(@Qualifier("customDataSourcePropertiesBean") DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
此数据源构建器不会尝试读取 application-qa.properties 中的 jndi 配置,并自动故障返回到 application.properties 返回错误的数据库连接。解决方法相当简单——测试您所处的环境并自定义创建的数据库连接类型。调试这是一个熊,因为症状是应用程序似乎忽略了应用程序-qa.properties。我分享是为了让别人免于痛苦。将 spring.profiles.active=qa 等添加到您的属性文件中以了解您所处的环境:
@Value("${spring.profiles.active}")
String profile;
@Value("${spring.custom.jndi-name}")
String jndi;
@Primary
@Bean(name="customDataSourcePropertiesBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSourceProperties customDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name="customDataSourceBean")
@ConfigurationProperties("spring.custom.datasource")
public DataSource customDataSource(@Qualifier("customDataSourcePropertiesBean") DataSourceProperties properties) {
if(profile.equals("localhost")) {
return DataSourceBuilder
.create()
.username(properties.getDataUsername())
.password(properties.getPassword())
.url(properties.getUrl())
.driverClassName(properties.getDriverClassName())
.build();
}else {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource(jndi);
}
}
就我而言,当我使用 Spring Boot App 启动我的应用程序时,数据库配置在应用程序-dev.properties 上读取,当我在 tomcat 上发布时,使用数据源,有必要添加一个验证来检查我的配置文件是否是 prod,在这种情况下,我进行了 jndi 查找
@Bean(name = "dsName")
@ConfigurationProperties("ds.datasource.configuration")
public DataSource dataSource(@Qualifier("dsProperties") DataSourceProperties db1DataSourceProperties)
{
if(Arrays.asList(environment.getActiveProfiles()).contains("prod"))
{
final JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("java:comp/env/jdbc/DS1");
}
else
{
return db1DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}