Spring Boot組み込みTomcatにおけるJNDIマルチデータソースの統合

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://www.java4s.com/spring-boot-tutorials/spring-boot-configure-datasource-using-jndi-with-example/

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.ymlapplication.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

以上です。お疲れ様でした!

タグ: Spring Boot Tomcat JNDI データソース MyBatis

9月8日 04:30 投稿