- PR -

ExtendedPropertiesの自動読み込みについて

投稿者投稿内容
どんたくお
ベテラン
会議室デビュー日: 2005/08/29
投稿数: 88
投稿日時: 2005-10-12 12:27
みなさん、こんにちは。

現在、下記の環境でWEBアプリケーションを構築しております。
FedoreCore2
J2SDK 1.4.1_08
Tomcat5

プロパティファイルの扱いで、何かよいライブラリがないかなと思って、探していたところJakarta commonsの
org.apache.commons.collections.ExtendedProperties
を見つけました。

参照プロパティやコレクション取得などに対応しており、便利そうだなと思って、導入しようと思いました。
ExtendedPropertiesクラスを使ってのプロパティファイルの読み込みは問題なくできました。
しかし、プロパティファイルを更新してもTomcatを再起動しないと、設定が反映されません。
プロパティファイルを更新したら、自動的に再読み込みを行い、アプリケーションから参照した場合に更新したプロパティを使用できる仕組みを作ることは可能でしょうか。
もしくは、そういう仕組みが既にありましたら、ご教授いただけると幸いです。

ディレクトリ構成は以下のようになっております。(パッケージは省略してあります)
/webapps/WEB-INF/classes/Prop.java
/webapps/WEB-INF/classes/prop.properties


よろしくお願いします。
takashi
ベテラン
会議室デビュー日: 2004/02/12
投稿数: 79
お住まい・勤務地: 東京
投稿日時: 2005-10-12 16:18
こんにちは。

TOMCATを再起動しないと反映されないということは、TOMCAT起動時に1度だけプロパティファイルを読み込み、後はサーブレットコンテキスト等にキャッシュしているということでしょうか?

もしそうであれば、タイムスタンプを用いて更新をチェックするとかはどうですか?
例えば、
1.TOMCAT起動時にプロパティファイルを読み込み、プロパティファイルのタイムスタンプをサーブレットコンテキストにセット。
2.ExtendedPropertiesオブジェクトを呼び出すときに現在のプロパティファイルのタイムスタンプを確認し、サーブレットコンテキストに格納しているタイムスタンプと比較

3.更新されていれば再読み込み

めんどくさいですね^−^;
ExtendedPropertiesを扱うユーティリティクラスを作成してしまえばそうでもないかも・・・?

あとは、プロパティファイルがあまり大きくなくて、パフォーマンスに問題がなさそうなら毎回読み込むとか?

あまりたいしたこと書けませんでしたが何かの参考になれば幸いです。
どんたくお
ベテラン
会議室デビュー日: 2005/08/29
投稿数: 88
投稿日時: 2005-10-12 19:06
takashiさん、ご返信いただきましてありがとうございます。

すみません。一番大事な事が抜けておりました。
実際には、下記のようなクラスになっております。

public class Prop {
private static ExtendedProperties props = null;

private Prop() {}

public static String getString(String key) {
if (props == null) {
loadPropertie();
}

return props.getString(key);
}

private static void loadPropertie() {
props = new ExtendedProperties();

InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream("prop.properties"));
props.load(in, "Windows-31J");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
}
}
}
}
}

サーブレットからは、
Prop.getString("hoge");
という感じで使用します。

この状態だと、一度読み込んだものをクラス内で保持しているので、プロパティファイルを変更しても、反映されません。
Tomcatの場合、server.xmlの設定によっては、クラスファイルが更新された場合に、自動的に反映されますが、イメージ的にはそんなのを考えていました。

やっぱり、難しいですかね・・・。
それか、getString時に、プロパティファイルが変更されていないか確認するかですよね・・・。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-10-12 19:36
自動でのリロードを行わせるには、
コード:
in = new BufferedInputStream(new FileInputStream("prop.properties")); 


ではなく、
コード:
ClassLoader loader = Thread.currentThread().getContextClassLoader();
in = new BufferedInputStream(loader.getResourceAsStream("prop.properties")); 


という様に、クラスローダでロードさせます。
どんたくお
ベテラン
会議室デビュー日: 2005/08/29
投稿数: 88
投稿日時: 2005-10-12 20:24
かつのりさん、ご返信いただきまして、ありがとうございます。
> ClassLoader loader = Thread.currentThread().getContextClassLoader();
> in = new BufferedInputStream(loader.getResourceAsStream("prop.properties"));
かつのりさんからご教授いただきました方法で、プロパティファイルを取得してみたのですが、
java.io.IOException: Stream closed
が出力されてしまいます。
検証用に下記を実行してみました。

System.out.println("1");
in = new BufferedInputStream(loader.getResourceAsStream("prop.properties"));
System.out.println("2");
props.load(in, "Windows-31J");
System.out.println("3");

コンソールには、
1
2
と出力されますので、
props.load()
にて、java.io.IOExceptionが出ているようです。

また、prop.propertiesは正しく配置されておりました。
// Fileクラスのexsist()を使って確認しました。


もしかして、prop.propertiesファイルの置き場所や、ClassLoaderの使い方が違っていますでしょうか。

引き続き、ご教授いただけると幸いです。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-10-12 20:41
System.out.println(loader);
System.out.println(loader.getResourceAsStream("prop.properties"));
上記ソースで何が出力されますか?

BufferedInputStreamでラップせず、直接クラスローダからのストリームを渡すとどうなりますか?
どんたくお
ベテラン
会議室デビュー日: 2005/08/29
投稿数: 88
投稿日時: 2005-10-12 20:59
かつのりさん、またまたご返信いただきまして、本当にありがとうございます。

無事、出力されるようになりました。
実は、ClassLoaderの仕組みをあまりよく知らずに、クラスからの相対パスでプロパティファイルを指定すればよいだろうと思っていたのですが、パッケージパスで指定しなければならなかったのですね。
今回、getResourceAsStreamの引数に、プロパティファイルのパッケージパス
/jp/****/****/prop.properties
と指定したら、うまいことプロパティ出力でき、さらにプロパティファイル更新時の自動読み込みも行うことができました。

皆様のおかげで、なんとかここまでこれました。
本当にありがとうございます。

最後に一点だけご質問なのですが、
finally {
if (in != null) {
try {
in.close();
}
}
}

という風に、InputStreamをクローズしています。
この用に、自動読み込みを行う場合も、
プロパティファイルの読み込みが完了したら、
in.close()
で閉じる方がよいのでしょうか。
コメントアウトしても、問題なく動作はしたのですが、もしかしてずっと
in.close()
せずに、ずっと開いておかないと動作に影響がでるのかと思い、ご質問させていただきました。


かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2005-10-12 21:17
ストリームは基本的に閉じるべきです。

実際には一度だけ読み込むだけのストリームの閉じ忘れぐらいで
問題になる事はないと思いますが。(楽観視です・・・)


余談になりますが、Strutsでも同様な方法でstruts-config.xmlの更新時に
自動リロードが可能になります。

通常struts-config.xmlは、FileInputStreamで読み込まれているので
自動リロードの対象となりませんが、
ActionServletのinitメソッドをオーバーライドして、
ClassLoaderから1度だけgetResourceで参照してしまいましょう。
更新するとリロードが行われます。

クラスパスのルートより上でも、../等で参照ができます。

スキルアップ/キャリアアップ(JOB@IT)