JNDIデータソースとは何か?
百度百科による説明を参照する
JNDI(Java Naming and Directory Interface、Java名前とディレクトリインターフェース)は、SUNが提供する標準的なJava名前システムインターフェースであり、JNDIは統一されたクライアントAPIを提供し、さまざまなアクセスプロバイダーインターフェースJNDIサービスサプライヤーインターフェース(SPI)の実装を通じて、管理者がJNDI APIを特定の名前サービスやディレクトリシステムにマッピングすることで、Javaアプリケーションがそれらの名前サービスやディレクトリシステムとの間で相互作用できるようにする。
読んでいて抽象的だと思いませんか?以下の点を理解することが重要です。
(1)JNDIはJ2EE規格の一つです。
(2)JNDIは主に2つの部分から構成されます:アプリケーションプログラミングインターフェースとサービスプロバイダインターフェース。アプリケーションプログラミングインターフェースは、Javaアプリケーションが各種名前およびディレクトリサービスにアクセスする機能を提供し、サービスプロバイダインターフェースは任意のサービスプロバイダが使用する機能を提供します。
(3)J2EE規格では、すべてのJ2EEコンテナがJNDI規格の実装を提供することを要求しています。
(4)JNDIの目的は、結合を緩和し、データベースとの直接的な結合を避けて、アプリケーションの設定および展開を容易にすることです。
これらの概念は専門家ブログからの引用です。以降の内容は筆者の経験に基づくものです!
JNDIの登場により、データベース接続コードはコンテナ(Tomcat、JBOSSなど)に委ねられることになりました。これにより、開発者はデータベースの設定やドライバーの選択などを気にする必要がなくなります。
従来のJNDIはWebコンテナに依存しており、例えばSpringフレームワークにおいて、コンテナ内でデータソース(または複数のデータソース)を設定し、その後Springプロジェクトの設定ファイルでデータソース名を指定して、WAR形式でコンテナにデプロイすればJNDIデータソースを利用できます。
Springプロジェクトの外部TomcatでのJNDIデータソース統合については以下を参照してください:
https://www.cnblogs.com/springboot-wuqian/archive/2004/01/13/9418180.html
https://cnsyear.com/posts/9b26f7c2.html
https://cnsyear.com/posts/ceb1797.html
今日はSpring Bootの組み込みTomcatにおけるJNDIデータソース統合についてです。理論的にはSpring Bootが組み込みTomcatを使用しているため、JNDIの統合も可能ですが、実際に試すと多くの困難とハマりどころがありました。本記事ではSpring Bootの組み込みTomcatでのJNDIデータソース統合方法について解説します。
Spring Boot組み込みTomcatによるJNDI統合の開始
1,依存関係の追加
必要な依存関係には、MySQLドライバとMyBatis Starterが含まれます。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
上記の依存関係は必須です。データベースへの接続と操作には不可欠です。重要なのは以下のTomcat依存関係で、これを忘れると1日悩まされました。この依存関係がないと、データソース情報を設定しても「データソースが見つからない」や「データソースの作成に失敗する」というエラーが発生します。
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>${tomcat.version}</version>
</dependency>
2,アプリケーション起動クラス
起動クラスに以下のアノテーションを追加します。
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
このアノテーションは、Spring Bootの自動設定プロセスにおいてデータソースの自動構成を除外します。これにより、application.ymlやapplication.propertiesにデータソースの設定がなくても正常に動作します。設定がない場合、自動構成によってエラーが発生します。
これは他の開発者の経験則です。しかし、設定しない場合でも動作することを確認しました。混乱しました。
3,データソース情報の設定
データソース設定クラスを作成し、データソース情報を定義します。複数のデータソースには複数のResourceを設定します。
@Configuration
public class DBConfiguration {
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
tomcat.enableNaming(); // デフォルトで無効になっているJNDI名前解決を有効化
return super.getTomcatWebServer(tomcat);
}
@Override
protected void postProcessContext(Context context) {
// データソース1
// ContextResourceオブジェクトを構築し、Contextに追加
ContextResource resource = new ContextResource();
resource.setName("jdbc/MyFirstMySql");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver");
resource.setProperty("url", "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC");
resource.setProperty("username", "root");
resource.setProperty("password","1234");
context.getNamingResources().addResource(resource);
// データソース2
// ContextResourceオブジェクトを構築し、Contextに追加
ContextResource resource1 = new ContextResource();
resource1.setName("jdbc/MySecondMySql");
resource1.setType(DataSource.class.getName());
resource1.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver");
resource1.setProperty("url", "jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC");
resource1.setProperty("username", "root");
resource1.setProperty("password","1234");
context.getNamingResources().addResource(resource1);
super.postProcessContext(context);
}
};
return tomcat;
}
}
4,YAMLファイルの設定
YAMLファイルでは使用するデータソース名のみを指定すれば十分です。他の設定は不要です。
spring:
datasource:
jndi-name: jdbc/MySecondMySql
これでJNDIデータソースの統合は完了です。次にテストを実施します。
5,テストの実行
Mapperファイルを作成し、Controllerに注入してテストを行います。プロジェクトを実行してアクセスします。
contentテーブルは両方のデータベースに存在しますが、guliデータベースでは複数のレコードがあり、testデータベースでは1つのレコードしかありません。これにより、結果の違いを確認できます。
@Mapper
public interface TestMapper {
@Select(value = "select * from content")
List<Map> getList();
}
@Autowired
TestMapper testMapper;
@RequestMapping("/getList")
@ResponseBody
public List<Map> getList(){
return testMapper.getList();
}
まず、YAML設定のJNDIデータソース名をMyFirstMySqlに変更し、プロジェクトを再起動して、http://localhost:8080/getListにアクセスします。
次に、YAML設定のJNDIデータソース名をMySecondMySqlに変更し、プロジェクトを再起動して同じインターフェースにアクセスします。
まとめ
以下の4つの状況におけるJNDIデータソース統合の違いに注意が必要です。
1,Spring外部コンテナでのJNDI統合 2,Spring Boot外部コンテナでのJNDI統合 3,Spring Boot 1.X内部コンテナでのJNDI統合 4,Spring Boot 2.X内部コンテナでのJNDI統合
詳細は以下を参照してください:
https://www.cnblogs.com/springboot-wuqian/archive/2004/01/13/9540439.html
以上です。お疲れ様でした!