web-dev-qa-db-ja.com

PropertyPlaceholderConfigurerで使用する環境固有のプロパティをロードしますか?

これはかなり一般的な問題のように思えますが、最良の方法についてコンセンサスが得られていないため、ここで質問を投げかけています。

私はSpring BatchとSpringを使用してコマンドラインJavaアプリケーションに取り組んでいます。PropertyPlaceholderConfigurerと一緒にプロパティファイルを使用していますが、最善の方法が少しわかりません複数の環境(dev、testなど)のプロパティファイルを処理します。グーグルは、プロパティを読み込むプログラム的な方法(つまり、Javaコード自体)のみを有効にします。私がやっていることのために働く。

私が検討した1つのアプローチは、単に各環境のプロパティファイルをサーバーに配置し、コマンドライン引数を介してファイルのディレクトリをクラスパスに追加することですが、その方法を使用してファイルをロードするのに問題があります。

私が検討しているもう1つの方法は、すべてのプロパティファイルをjarに含め、システムプロパティまたはコマンドライン引数を使用して、実行時にプロパティファイルの名前を入力することです:

<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:job.properties.${env}</value>
        </list>
    </property>
</bean>

私は後者の解決策に傾いていますが、私が見落としているより良い方法があるかどうかも調べています。

また、ビルドではなく実行時に置換を行う必要があることにも言及する必要があります。使用を制限されているプロセスには、環境を介してプロダクションにプロモートされる単一のビルドが必要なので、MalaまたはAntの代替を使用することはできません。

31
Ickster

同意します-さまざまなコンテキストにまったく同じペイロードをデプロイするため、ビルド時の構成であってはなりません。

PropertyPlaceHolderConfigurerのLocationsプロパティは、さまざまなタイプのリソースを取ることができます。ファイルシステムリソースまたはURLにすることもできますか?したがって、設定ファイルの場所をローカルサーバー上のファイルに設定すると、実行するたびにそのサーバー上の設定ファイルで指定されたモードで実行されます。特定の実行モード用の特定のサーバーがある場合、これは正常に機能します。

行間を読むと、同じサーバー上で異なるアプリケーションを同じモードで実行したいようです。この場合、コマンドラインパラメーターを使用して構成ファイルの場所を渡すことをお勧めします。この値をPropertyPlaceHolderConfigurerに渡すのは少し難しいですが、不可能ではありません。

3
Michael Wiles

基本的に、別の環境にドロップしたい完成したJARがあり、修正なしで実行時に適切なプロパティを取得します。それが正しい場合、次のアプローチが有効です。

1)ユーザーのホームディレクトリ内のプロパティファイルの存在に依存します。

次のように、JARの外部のプロパティファイルを参照するようにPropertyPlaceholderConfigurerを構成します。

<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="order" value="1"/>
    <property name="locations">
      <list>
        <!-- User home holds secured information -->
        <value>file:${user.home}/MyApp/application.properties</value>
      </list>
    </property>
  </bean>

オペレーティングシステムはapplication.propertiesファイルの内容を保護し、適切なユーザーのみがアクセスできるようにします。アプリケーションを最初に実行したときにはこのファイルは存在しないため、起動時に重要な値(ユーザー名、パスワード、Hibernateダイアレクトなど)をユーザーに問い合わせる簡単なスクリプトを作成します。コマンドラインインターフェイスの広範なヘルプと適切なデフォルト値を提供します。

2)アプリケーションが制御された環境にあり、データベースを見ることができる場合、上記の手法1)を使用して基本的な資格情報を作成し、コンテキスト起動時にデータベースに接続し、値の読み取りを使用して置換を実行することで問題を軽減できますJDBC経由。アプリケーションの起動には2段階のアプローチが必要です。段階1では、JdbcTemplateと関連するDataSourceを設定するapplication.propertiesファイルで親コンテキストを呼び出します。フェーズ2は、JdbcTemplateをJdbcPropertyPlaceholderConfigurerで構成されたとおりに使用できるように、親を参照するメインコンテキストを呼び出します。

この種のコードの例は次のとおりです。

public class JdbcPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

  private Logger log = Logger.getLogger(JdbcPropertyPlaceholderConfigurer.class);
  private JdbcTemplate jdbcTemplate;
  private String nameColumn;
  private String valueColumn;
  private String propertiesTable;

  /**
   * Provide a different prefix
   */
  public JdbcPropertyPlaceholderConfigurer() {
    super();
    setPlaceholderPrefix("#{");
  }

  @Override
  protected void loadProperties(final Properties props) throws IOException {
    if (null == props) {
      throw new IOException("No properties passed by Spring framework - cannot proceed");
    }
    String sql = String.format("select %s, %s from %s", nameColumn, valueColumn, propertiesTable);
    log.info("Reading configuration properties from database");
    try {
      jdbcTemplate.query(sql, new RowCallbackHandler() {

        public void processRow(ResultSet rs) throws SQLException {
          String name = rs.getString(nameColumn);
          String value = rs.getString(valueColumn);
          if (null == name || null == value) {
            throw new SQLException("Configuration database contains empty data. Name='" + name + "' Value='" + value + "'");
          }
          props.setProperty(name, value);
        }

      });
    } catch (Exception e) {
      log.fatal("There is an error in either 'application.properties' or the configuration database.");
      throw new IOException(e);
    }
    if (props.size() == 0) {
      log.fatal("The configuration database could not be reached or does not contain any properties in '" + propertiesTable + "'");
    }
  }

  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }

  public void setNameColumn(String nameColumn) {
    this.nameColumn = nameColumn;
  }

  public void setValueColumn(String valueColumn) {
    this.valueColumn = valueColumn;
  }

  public void setPropertiesTable(String propertiesTable) {
    this.propertiesTable = propertiesTable;
  }

}

上記は、Springで次のように構成されます(orderプロパティは、通常の$プレフィックス付きプレースホルダーの後に来ることに注意してください):

  <!-- Enable configuration through the JDBC configuration with fall-through to framework.properties -->
  <bean id="jdbcProperties" class="org.example.JdbcPropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="order" value="2"/>
    <property name="nameColumn" value="name"/>
    <property name="valueColumn" value="value"/>
    <property name="propertiesTable" value="my_properties_table"/>
    <property name="jdbcTemplate" ref="configurationJdbcTemplate"/> <!-- Supplied in a parent context -->
  </bean>

これにより、Spring構成でフォローが発生します。

<!-- Read from application.properties -->
<property name="username">${username}</property>  
...
<!-- Read in from JDBC as part of second pass after all $'s have been fulfilled -->
<property name="central-thing">#{name.key.in.db}</property> 

3)もちろん、Webアプリケーションコンテナーを使用している場合は、JNDIを使用するだけです。しかし、そうではありません。

お役に立てれば!

11
Gary Rowe

Spring XMLで<context:property-placeholder location="classpath:${target_env}configuration.properties" />を使用し、コマンドライン引数(${target_env})を使用して-Dtarget_env=test.を構成できます。

Spring 3.1以降では、<context:property-placeholder location="classpath:${target_env:prod.}configuration.properties" />を使用してデフォルト値を指定できるため、コマンドラインで値を設定する必要がなくなりました。

Maven ISオプションの場合、プラグインの実行中、たとえばテストまたは統合テストの実行中にSpring変数を設定できます。

<plugin>
    <groupId>org.Apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <systemPropertyVariables>
            <target_env>test.</target_env>
        </systemPropertyVariables>
    </configuration>
</plugin>

異なるMavenプロファイルも機能すると思います。

8
enno

Spring Property Placeholder Configurer –それほど明白ではないいくつかのオプション

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:db.properties"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="${db.url.${mode}}" />
    <property name="username" value="${db.username.${mode}}" />
    <property name="password" value="${db.password.${mode}}" />
</bean>

${db.username.${mode}}:ここで、「モード」はプロジェクトモード(環境)を定義します-dev/prodプロパティファイルは次のようになります。

#Database properties
#mode dev/prod
mode=dev

#dev db properties
db.url.dev=jdbc:mysql://localhost:3306/dbname
db.username.dev=root
db.password.dev=root

#prod db properties
db.url.prod=jdbc:mysql://localhost:3306/dbname
db.username.prod=root
db.password.prod=root
7
Navrattan Yadav

過去にこれを通常行ってきた方法は、パッケージ/展開時に何らかの方法で環境(dev/test/prod)の置換を実行することです。

これにより、正しい構成ファイルをサーバー上の正しい場所にコピーするか、正しい構成ファイルを展開パッケージにバンドルすることができます。 Ant/Mavenを使用する場合、これは簡単に達成できます。どのビルドツールを使用していますか? Ant/Maven、値を置換する機能を提供する必要があります。

PropertyPlaceholderConfigurerを使用する別の代替手段は、SYSTEM_PROPERTIES_MODE_OVERRIDEプロパティの代替手段です。これを使用して、システムプロパティを介してロードするプロパティファイルの場所を設定できます。以下を参照してください。

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html#SYSTEM_PROPERTIES_MODE_OVERRIDE

お役に立てば幸いです。

3
Jon

ビルド時の置換では、変数置換にMavenビルドプロパティを使用します。 Mavenのsettings.xmlファイルでロードするプロパティを決定できます。このファイルは環境に固有のものである可能性があります。 PPC=これを参照してください blog

1
harschware

こんにちは、Spring in Actionを読んだ後、Springが提供するソリューションを見つけました。プロファイルまたは条件付き:複数のプロファイルを作成できます。 test、dev、prodなど。

Springは、アクティブなプロファイルを決定する際に、spring.profiles.activeとspring.profiles.defaultの2つの個別のプロパティを尊重します。 spring.profiles.activeが設定されている場合、その値はアクティブなプロファイルを決定します。ただし、spring .profiles.activeが設定されていない場合、Springはspring.profiles.defaultを探します。 spring.profiles.activeもspring.profiles.defaultも設定されていない場合、アクティブなプロファイルは存在せず、プロファイル内にあると定義されていないBeanのみが作成されます。

これらのプロパティを設定する方法はいくつかあります。1 DispatcherServletの初期化パラメータとして2 Webアプリケーションのコンテキストパラメータとして3 JNDIエントリとして4環境変数として5 JVMシステムプロパティとして6統合テストクラスで@ActiveProfilesアノテーションを使用する

1
Navrattan Yadav

クラスパスオプションを使用し、Jettyの環境ごとにクラスパスを調整します。 jetty-maven-pluginでは、testclassesのディレクトリを設定し、そこにtestresourcesを配置できます。

非ローカル環境(テスト/本番)の場合、環境フラグを使用し、適切なファイルを$ JETTY_HOME/resourcesフォルダー(Jettyのクラスパスに組み込まれています)に送信します

0
Mond Raymond