« Apache Wicketを使ってみる[3] -Model編- | トップページ | Apache Wicketを使ってみる[4] -認証/認可編- »

2019年9月14日 (土)

MavenのJettyにDataSourceを設定するのに苦労した話

0. やっぱりデータソースは外に出したいのです

前回のデータアクセスの話では、

val database: Sql2o = Sql2o("jdbc:mysql://localhost:3306/mydb", "mydbadmin", "mydbadmin")

と、ソースコードに直接書いていたけれど、実際の運用を考えるとDBの接続先設定とプロダクションコードは極力分離したいところ。

幸いにも、Mavenで作ったプロジェクトのアーキタイプにはJettyがdependencyに組み込まれていて、test側に開発サーバとしてJettyを起動するときの処理が最初から入っている。
ここに DataSource 設定を書いてやれば、理屈の上ではプロダクションコードからDBの接続先設定を分離できることになる。

で、前置きが長くなってしまったけど、Mavenで依存に入っているJettyにDataSourceを設定するのに結構苦労をしたので、その時の備忘録的なメモを書いてみる。

1. やること(というかやったこと)

やったことをざっくりまとめると、以下のとおり。

  1. pom.xmlに依存とプラグイン設定を追加
  2. Jettyの設定ファイル追加
  3. web.xmlにDataSourceルックアップ設定を追加
  4. DataSourceを使うようデータアクセス部分を変更

1. pom.xmlに依存とプラグイン設定を追加

なにはなくともdependencyに必要なライブラリを入れなければならない。
今回はコネクションプールライブラリを挟む方針で、高性能を謳っていることで話題のHikariCPを使ってみることにする。

<dependencies>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.17</version>
    <!-- Jettyがtestスコープで動くのでそちらに合わせる -->
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.3.1</version>
    <!-- Jettyがtestスコープで動くのでそちらに合わせる -->
    <scope>test</scope>
  </dependency>
</dependencies<

Jettyがtestスコープで動くので、コネクションプールとJDBCドライバもそれに合わせておく。

次に、JettyがHikariCPとconnector-jを扱う設定を読み込めるようにするのだけど、これはMavenプラグインの設定をいじる必要がある。
追加するとこんな感じになるはず。

<plugins>
  <plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>${jetty9.version}</version>
    <configuration>
      <-- 追加、testスコープのclasspathを優先する設定 -->
      <useTestScope>true</useTestScope>
      <-- 追加ここまで -->
      <systemProperties>
        <systemProperty>
          <name>maven.project.build.directory.test-classes</name>
          <value>${project.build.directory}/test-classes</value>
        </systemProperty>
      </systemProperties>
      <jettyXml>
        ${project.basedir}/src/test/jetty/jetty.xml,${project.basedir}/src/test/jetty/jetty-ssl.xml,${project.basedir}/src/test/jetty/jetty-http.xml,${project.basedir}/src/test/jetty/jetty-https.xml
      </jettyXml>
      <!-- 以下追加 -->
      <webApp>
        <!-- web.xml を読み込む先を指定する設定 -->
        <descriptor>${project.basedir}/src/main/webapp/WEB-INF/web.xml</descriptor>
        <!-- 「データソースとして定義する内容」を書いたファイルを読み込む設定 -->
        <jettyEnvXml>${project.basedir}/src/test/jetty/jetty-env.xml</jettyEnvXml>
      </webApp>
      <!-- 追加ここまで -->
    </configuration>
  </plugin>
</plugins>

2. Jettyの設定ファイル編集

前述のpom.xml

に追加したjetty-env.xmlを、src/test/jettyに作る。

設定例をググっていると、 Configure の class に org.eclipse.jetty.webapp.WebAppContext を使う例が結構ひっかっかると思うけど、これをやると ClassCastException で設定に失敗するので org.eclipse.jetty.maven.plugin.JettyWebAppContext に変更している。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- Configure の class は、 Maven プラグインから動くのでこっちを使う -->
<Configure id="wac" class="org.eclipse.jetty.maven.plugin.JettyWebAppContext">
  <New id="myDS" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg><Ref refid="wac" /></Arg>
    <!-- ここが DataSource の名前になる -->
    <Arg>jdbc/datasource</Arg>
    <Arg>
      <New class="com.zaxxer.hikari.HikariDataSource">
        <Arg>
          <New class="com.zaxxer.hikari.HikariConfig">
            <!-- 以下 setter 部分の意味は JavaDoc とかを参照のこと -->
            <Set name="maximumPoolSize">20</Set>
            <Set name="driverClassName">com.mysql.cj.jdbc.Driver</Set>
            <Set name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</Set>
            <Set name="username">mydbadmin</Set>
            <Set name="password">mydbadmin</Set>
          </New>
        </Arg>
      </New>
    </Arg>
  </New>
</Configure>

3. web.xmlにDataSourceルックアップ設定を追加

下回りは設定できたので、プロダクションコードに関連する箇所をいじって、 DataSource をルックアップできるようにする。

pom.xmlに追加したとおり、/src/main/webapp/WEB-INF/web.xmlに以下を追加。

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">

  <!-- "jdbc/datasource" をデータソースとして名付ける設定 -->
  <resource-ref>
    <res-ref-name>jdbc/datasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

</web-app>

4. DataSourceを使うようデータアクセス部分を変更

ここまでくれば DataSource をルックアップできるようになるので、接続設定を DataSource を使うように変更する。
例によって Kotlin で書いている。

open class DatabaseHelper {
    // init ブロックで初期化されるので空でよい
    //val database: Sql2o = Sql2o("jdbc:mysql://localhost:3306/mydb", "mydbadmin", "mydbadmin")
    val database: Sql2o

    init {
        // InitialContext から "jdbc/datasource" をルックアップする
        val context = InitialContext()
        val datasource = context.lookup("java:comp/env/jdbc/datasource") as DataSource
        // ルックアップした DataSource オブジェクトで Sql2o を初期化
        database = Sql2o(datasource)
    }
}

この状態で mvn package を実行して war を作り、 Tomcat とかのアプリケーションコンテナにデプロイしてもちゃんと動く。ここまで来るのに長かった....。

|

« Apache Wicketを使ってみる[3] -Model編- | トップページ | Apache Wicketを使ってみる[4] -認証/認可編- »

コメント

コメントを書く



(ウェブ上には掲載しません)




« Apache Wicketを使ってみる[3] -Model編- | トップページ | Apache Wicketを使ってみる[4] -認証/認可編- »