Typesafe Config について

この記事は Play framework 2.x Java and 1.x Advent Calendar 2013 の 12 日目です。

Typesafe Config は Play framework でアプリケーションの設定に使われているライブラリです。Typesafe 製ですが、Play や Scala に依存してはいません。使い勝手が良く、Play を使わないような状況でもお勧めできます。

特徴は?

  • JSON 上位互換で .properties ファイル風にも書けるファイル形式 (HOCON形式)
  • 複数の設定情報の組み合わせがしやすい
  • 10s 等の期間および 512MB 等のデータサイズの記法のサポート
  • Typesafe 製だけど Scala 依存ではない

以下、使い方を解説します。サンプルソースは以下に置いてあります。

https://github.com/wm3/advent-calendar-typesafe-config

とりあえず、インストールしてみる

Maven からインストールしてみます。

<project ...>
    <!-- pom.xml -->
    ...
    <dependencies>
    ...
        <dependency>
           <groupId>com.typesafe</groupId>
           <artifactId>config</artifactId>
           <version>1.0.2</version>
        </dependency>
    ...
</project>

上のように使用ライブラリを追加する事で利用できるようになります。 Typesafe Config は Maven Central で配布されているのでリポジトリの設定等は必要ありません。 mavenrepository.com からも検索できます。

コマンドラインを使う場合は、以下のコマンドを実行して使用ライブラリのツリーが確認できます。

% mvn dependency:tree
...(中略)...
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ advent-calendar-typesafe-config --- 
[INFO] jp.w3ch.examples:advent-calendar-typesafe-config:jar:0.0.1-SNAPSHOT 
[INFO] \- com.typesafe:config:jar:1.0.2:compile
...(中略)...
%  

ビルド結果に「com.typesafe:config:1.0.2:compile」 の文字列が書かれているでしょうか?

ハロー、ワールド!

Java から利用してみます。

package jp.w3ch.examples;

import com.typesafe.config.*;

public class MyApp1 {

     public static void main(String[] args) {
          Config config = ConfigFactory.load("myapp1/hello");

          System.out.println("Hello " + config.getString("app.message") + "!");
     }
}

設定ファイルは以下のようになります。

// myapp1/hello.conf
app.message = World

実行すると、

Hello World!

と表示されます。

上の設定は .properties ファイルに似たような形式になりますが、このようにも書けます。

app {
    message = "World"
}

また、以下のようにも書けます。

{
    "app": {
        "message": "World"
    }
}

最後の書き方は JSON そのものです。Typesafe Config は内部的には各設定の要素を JSON のオブジェクト(もしくは文字列/数字等)のように扱いします。設定のルートは一つのオブジェクトとして扱われます。

環境に応じて別のDBや連携サービスを指定する

Web アプリケーションでは、実行環境に応じて細かい設定を変えるケースが大半だと思います。その場合は、他のファイルをインポートする機能が役に立ちます。

例えば、開発環境向けの設定

//  myapp2/development.conf
app.db = {
    host: localhost,
    user: myapp,
    password: secret,
    url: "jdbc:postgresql://"${app.db.host}":5432/myapp"
}

…と、幾つかの設定を上書きし、他の設定は引き継いだ、本番環境向けの設定を用意します。

//  myapp2/production.conf
include "development"

// override some configurations in development.conf
app {
    db.host = "10.0.0.49"
    db.password = "hi-mi-tsu"
}

以下のプログラムを実行してみます。

package jp.w3ch.examples;

import com.typesafe.config.*;

public class MyApp2 {

    public static void main(String[] args) {
        Config config = ConfigFactory.load("myapp2/" + args[0]);

        System.out.println("database: " + config.getString("app.db.url"));
        System.out.println("    user: " + config.getString("app.db.user"));
        System.out.println("password: " + config.getString("app.db.password"));
    }
}

開発向けに実行すると、以下のように出力されます。

database: jdbc:postgresql://localhost:5432/myapp
    user: myapp
password: secret

本番環境向けに実行すると、以下のように出力されます。

database: jdbc:postgresql://10.0.0.49:5432/myapp
    user: myapp
password: hi-mi-tsu

開発環境向けと本番環境向けを見比べると、ほとんどの設定は引き継がれていますが、 app.db.password が上書きされています。また、接続先の URL はホストの部分だけ変更されています。これは、 development.conf で app.db.host 設定を変数として使って URL を生成していて、その app.db.host は production.conf で上書きされているからです。

こんな感じに、 Typesafe Config は設定をうまくマージしてくれます。

期間やデータサイズを設定する

アプリケーションの設定にはタイムアウトやデータサイズの上限等を設定する事が多いと思います。 Typesafe Config には s(秒) や kB 等を認識する機能があります。

// myapp3/application.conf
app.timeout = 3s
app.fileSize  = 10MB

臨時で設定を上書きしたい!という時はシステムプロパティを使って上書きすることができます。 java コマンドで指定する場合は例えば以下のようになるでしょう。

% java -Dapp.timeout=10s (他のオプションメインクラス、引数等)

まとめ

Typesafe Config を紹介しました。まとめると以下のような特徴があります。

メンテナンスが楽

  • maven central repository で提供されている
  • コンパイル/実行時の依存ライブラリも無い(1.0.2 時点)
  • Scala が必要ではなく、ただの Java で使える

分かりやすく、柔軟性が高い

  • JSON っぽい形式、JSON と同じセマンティックス
  • 設定のマージがしやすい
  • 期間やデータサイズを指定する構文

アプリケーション設定は大抵はフレームワークが提供していますが、アプリケーションの管轄外の部分で設定を書きたくなった場合や、そもそもまともなフレームワークが使われていない場合など、ちょくちょく必要になる事があるように個人的には思います。また、設定ファイル形式が柔軟でない場合(.properties ...)等もあります。そういった時に Typesafe Config を使ってみてはいかがでしょうか?

明日はけーえむさん(2回目)です!