0

実行時にプロパティ セットをロードするサービスを作成するための最良の方法は何ですか (bean は "xyz" を渡され、xyz.properties をロードします)。これらのプロパティ ファイルは、コマンドを入力してサービスを開始する前に、クラスパス外のフォルダーにドロップできる必要があります (編集: これは、プログラムの実行中にいつでも発生する可能性があります)。

これを行うためのシステムを 1 年以上使用していますが、Spring に移行して、コードをよりモジュール化し (DI を使用してサービスをより簡単にカスタマイズできます)、保守しやすくしています。環境を作成し、それを「this」で依存関係に渡す現在の方法は、IoC の観点からは逆さまに見えます。

プロパティ ファイルの名前をハードコーディングせずに PropertyPlaceholderConfigurer を使用する方法はありますか? たぶん、依存関係がロードできるサービスのコンストラクターに渡す変数への参照だけでしょうか? これまでのところ、サービスを作成し、構成なしでその依存関係を注入し、それぞれに対して個別のロード メソッドを呼び出してプロパティを渡す必要があるように見えますが、それは本当にSpringを使用していないようです.

ユース ケース: アプリはクライアント接続をさまざまなサーバーにプールし、他のアプリケーションからの要求をこれらのサーバーに転送します。新しいプロファイルは、アプリを停止したり再起動したりせずに、プログラマー以外でも追加できる必要があります。プロファイルには、ホスト、ポート、ログイン情報などの基本的な情報だけでなく、tcp/http、ssl/https (使用するクライアントの種類を決定する) を使用するかどうか、およびタイムアウトとプールの最小/最大/などのより複雑な情報も含まれます。など(デフォルト値が必要です)。

4

3 に答える 3

1

試してみましたがPropertyPlaceholderConfigurer、率直に言って、頭を包み込むことができませんでした。既存のオプションを使用する場合は十分に使いやすいですが、フレームワークを拡張することはできませんでした。

したがって、私のアプローチははるかに単純でした:

  1. @InjectConfig構成キーをパラメーターとして受け取るアノテーションを作成します。

  2. Bean/サービスで、この注釈を使用してフィールドまたはパブリック セッターに注釈を付けます。

  3. BeanPostProcessor「構成プロバイダー」からオプションを受け取り、それらをフィールド/セッターに挿入する を記述します。

  4. 必要なのは構成プロバイダーだけです。それをポストプロセッサに挿入すれば完了です。

注: セッターにアノテーションを付けることをお勧めします。これは、238576 個の構成ファイルのスマートな名前を考え出す必要なく、テストからサービスを簡単に構成できる (セッターを呼び出すだけ) ことを意味するためです。

編集多くの構成がある場合は、構成ファクトリの方が適している場合があります。

  1. 構成バンドルを記述するキーを作成します (通常、ここではタイプミスを防ぐために列挙型または新しい型を使用します)
  2. サービスを作成するときに、このキーをサービスに入れます (手動または Spring 経由)。
  3. Propertiesまたはを返すことができる設定ファクトリを作成Mapし、設定キーを指定します。
  4. このファクトリをサービスに挿入します

サービスの初期化コードで、キーを使用してファクトリ経由で構成を検索します。

このアプローチを使用すると、テストで常に同じものを返すダミー ファクトリと、生産用のより複雑なファクトリを作成できます。

実際のファクトリは、Spring を介して構成できるため、構成ファイルを探す場所がわかります。java.io.File1 つの方法は、構成キーごとに登録することです。これで、懸念事項 (サービスの構成と構成の読み込み) が完全に分離されました。

于 2013-08-19T13:41:26.983 に答える
0

最善の方法は、メインの ApplicationContext を含む ServiceManager を使用し、各 Service に、メイン コンテキストを親として独自の FileSystemXmlApplicationContext を次のように初期化させることです。

public class ServiceManager {

ApplicationContext appContext;
String APP_HOME = System.getProperty("user.home") + File.separator;

public void init() {
    //set main spring context
    appContext = new AnnotationConfigApplicationContext(AppConfig.class);
}

public void start(String serviceName) throws Exception {
    ApplicationContext serviceContext = new FileSystemXmlApplicationContext(
            new String[]{APP_HOME + serviceName + ".xml"}, //path to child ctx
            appContext); //reference to parent ctx to build hierarchy
    Service service = (Service) serviceContext.getBean("service");
    service.start();
}

}

ApplicationContext は複製するには少し重いですが、最近のメモリはかなり安価であり、これにより懸念事項が完全に分離されます。親コンテキストによって管理される共有ログとイベント システムがまだあり、各サービスは独自の構成で簡素化されています。2 つのサービスを使用して概念実証を構築しましたが、今のところ問題なく動作しているようです。他のサービスとテストが終了したら、別のコメントを追加します。

参考: http ://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/

于 2013-08-20T16:27:52.487 に答える
0

PropertyPlaceholderConfigurer は、アプリケーション コンテキストの初期化時に一度だけファイルを読み取り、初期化します。そのため、おそらく実行時に構成することはできません。しかし、変数を持つことができます。たとえば、私の場合、デフォルトのプロパティとユーザー固有のプロパティがあります。そのため、PropertyPlaceholderConfigurer は最初にクラスパスからプロパティを読み込み、その後、定義された場所 (ユーザーのホーム フォルダー) で追加のプロパティを見つけようとします。I ユーザーのプロパティ ファイルが存在するため、configurer がそれをロードしてプロパティをオーバーライドします。

これが私の例です:

<bean id="config" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound" value="true"/> <!-- do not throw exception if file not found -->
    <property name="locations">
        <list>
            <value>classpath:server.properties</value>
            <value>file:${user.home}/user.properties</value>
        </list>
    </property>
</bean>

この答えがまさにあなたが必要としているものかどうかはわかりません。しかし、私はあなたの実際の仕事が何であるかを推測しようとしています. そのため、プロパティにアクセスするたびにランタイムを再読み込みする必要がある場合は、以前と同じように手動で行う必要があります。これは、Spring アプリケーション コンテキストがアプリケーションの初期構成を構成するのに役立つためです。

于 2013-08-19T13:43:52.527 に答える