Application Serverの組み込み機能を使用してmultipleDataSourceを管理し、JNDIを使用してそれにアクセスしたい。 Spring JPAデータでSpringブートを使用しています。
単一のデータソースの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"/>
すべてが正常に動作します。
しかし、2つのデータソースを設定できない場合。
私は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
複数のデータソース用のJNDIを使用したSpringブートの詳細を教えてください。私は何日もこの構成を探していました。
2番目のトライアル スプリングブートドキュメント
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.secondary.jndi-name=jdbc/project
構成クラス。
@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サーバーは開始されていますが。エラーはログに出力されません。
3番目のトライアル: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
顧客スキーマにすべてのテーブルを作成しますが、他のテーブルも見つけられません(2番目のスキーマから)。
これは、3回目のトライアルのソリューションを少し変更したものです。このソリューションを検討してください(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リポジトリ。
これにはプレーンな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リソースもクローズ/シャットダウンされます。これは、共有環境で必要なものではありません。
それは私のために働き、より少ないコードが含まれています
@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リソースを設定します。これはEclipseで開始/停止できます。注-EclipseでTomcatをダブルクリックし、ワークスペースmetedataの使用を選択します。これは、アプリを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アノテーション付きクラスで、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がプロジェクトで使用されている場合は、上記のデータソースを提供してjdbcTemplate Beanを作成します
@Bean(name = "jdbcAbcTemplate")
public JdbcTemplate abcJdbcTemplate(@Lazy @Qualifier("abcDataSource")
DataSource refDS)
{
return new JdbcTemplate(refDS);
}
dataSourceタイプのプロパティを自動配線し、systemoutにその詳細を取得して、さらに調査します。
上記の回答は適切ですが、jndiと完全なデータ接続構成を混在させる場合の致命的な問題を説明するために、もう1つ追加します。典型的な開発環境では、ローカル開発環境でデータベース接続を完全に修飾し、qnなどにプッシュするときに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と完全修飾接続が自動的に検出され、アプリケーションコードに変更を加えることなくデータソースが返されます。独自のデータソースを定義すると、これは行われなくなります。次のような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
springのドキュメント で提案されているように、データソースBeanをそのように使用する-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に戻り、WRONGデータベース接続を返します。解決方法は非常に簡単です。現在の環境をテストし、作成されるデータベース接続のタイプをカスタマイズします。アプリケーションがapplication-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);
}
}