環境別に定義値を分けたいけれど意識はしたくない場合の小細工の一例

  • 4
    Like
  • 0
    Comment

はじめに

 データベースや外部サーバなどへの接続先情報や認証情報といった値は、開発中用の値と本番運用時用の値で別々の値を持ちたい、と思う事が大変よくあるかと思います。
 その際、同一の定義ファイルに

conf.properties
 #本番用接続先
 #url=http://example.com/
 #テスト用接続先
 url=http://test.example.com/

 …のような書き方をして、コメントの付け替えで対処する方をたまに見るのですが、(そうしなければならない明確な理由も無いのに)ソースコード側にベタで定数値を書くような色々と残念な方より遥かにマシであるとは言え、あまり良いやり方ではありません。
 一番の理由は、今の定義ファイルの内容がどちら側に向いた内容なのかを気にかけて把握していなければならない点が挙げられるでしょう。
 誰だって、間違って定義ファイルのコメントの付け替えを忘れたままテスト用の接続先に繋がっているものを本番用として表に出してしまった…という事故なんて想像したくはないものです。
 今日日の良くできたフレームワークでしたらこの辺の要望にきちんと対応しているものもあるのですが、今回はフレームワークに依存せずあまり手間暇をかけずに対処する一例を書いてみたいと思います。

コード

Configures.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 定義値のコンテナ
 */
public class Configures {
    /** システムプロパティのキー名 */
    public static final String PropKey = "Config";

    private static final Properties config = new Properties();

    /**
     * 初期化
     * @param filePath 定義ファイルへのパス
     */
    synchronized public static void initialize(String filePath) {
        try {
            load(new FileInputStream(filePath));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 初期化
     * @param in 定義ファイルへのStream
     */
    synchronized public static void initialize(InputStream in) {
        load(in);
    }

    private static void load(InputStream in) {
        try {
            config.load(in);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 定義値の読み出し
     * @param key キー項目
     * @return 定義値
     */
    public static String get(Environment key) {
        return get(key, null);
    }

    /**
     * 定義値の読み出し
     * @param key キー項目
     * @param defaultValue 初期値
     * @return 定義値
     */
    public static String get(Environment key, String defaultValue) {
        if (key == null) {
            throw new IllegalArgumentException("Environment is null");
        }
        return config.getProperty(key.getPropertyKey(), defaultValue);
    }

    private Configures() {
    }
}
Environment.java
/**
 * 定義ファイルのキー項目
 */
public enum Environment {

    /** 接続先URL */
    ConnectUrl("url"),;

    private final String key;

    /**
     * コンストラクタ
     * @param key 定義ファイル内でのキー名称
     */
    private Environment(String key) {
        this.key = key;
    }

    /**
     * プロパティキー取得
     * @return キー名
     */
    public String getPropertyKey() {
        return getPropertyKey(System.getProperty(Configures.PropKey));
    }

    /**
     * プロパティキー取得
     * @param envName 環境名
     * @return キー名
     */
    public String getPropertyKey(String envName) {
        if (envName == null || "".equals(envName)) {
            return key;
        }
        return String.format("%s.%s", key, envName);
    }
}

使い方

定義ファイルを次のように用意した上で

conf.properties
 url=http://localhost/
 url.Test=http://test.example.com/
 url.Release=http://example.com/

本番環境にシステムプロパティ”Config”を"Release"という値で定義します。
(※"-DConfig=Release"を実行時環境変数に加えるのが一番楽だと思います)

実コード内では、処理の冒頭に

 Configures.initialize(....)

を書き加え(WebアプリケーションならServletContextListenerあたりを使うと良いでしょう)

 String url = Configures.get(Environment.ConnectUrl);

とやると、システムプロパティを定義していない環境では"http://localhost/" 本番環境では"http://example.com/" の値が返ってくるようになります。

テストケースクラスなどでは、セットアップ用のメソッドで

 System.setProperty(Configures.PropKey, "Test");

とやれば"http://test.example.com/" の値が渡されます。