7.2. プロパティ管理¶
目次
7.2.1. Overview¶
本節では、プロパティの管理方法について説明する。
プロパティとして管理が必要となる値は、以下の2つに分類することができる。
項番 | 分類 | 説明 | 例 |
---|---|---|---|
環境依存設定値 | アプリケーションが動作する環境に応じて指定する値を変える必要がある設定値。 システム構成などの非機能要件に依存する。 |
|
|
アプリケーション設定値 | アプリケーションの動作をカスタマイズできる様にするための設定値。 アプリケーションの機能要件に依存する。 |
|
Note
本ガイドラインでは、これらの設定値については、プロパティとして管理(プロパティファイルに定義)することを推奨している。
これらの設定値をプロパティから取得する仕組みにしておくと、設定値を変更する際に、アプリケーション(warファイルやjarファイル)を再ビルドする必要がないため、テスト済みのアプリケーションをプロダクト環境にリリースする事が可能になる。
プロパティとして管理されている値は、以下の2箇所で利用することができる。
- bean定義ファイル
- DIコンテナで管理するJavaクラス
7.2.2. How to use¶
7.2.2.1. プロパティファイル定義方法について¶
<context:property-placeholder/>
タグを定義することで、JavaクラスやBean定義ファイル内でプロパティファイル中の値にアクセスできるようになる。<context:property-placeholder/>
タグは、指定されたプロパティファイル群を読み込み、@Value
アノテーションや、 Bean定義ファイル中で、${xxx}
形式で指定されたプロパティファイルのキー xxx
に対する値を取得できる。Note
${xxx:defaultValue}
形式で指定すると、プロパティファイルにキー xxx
の設定が存在しない場合にdefaultValue
を使用する。
以下に、プロパティファイルの定義方法について説明する。
bean定義ファイル
applicationContext.xml
spring-mvc.xml
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/> <!-- (1) -->
項番 説明 (1)locationに設定する値は、リソースのロケーションパスを設定すること。location属性には、カンマ区切りで複数のパスを指定することができる。上記設定により、クラスパス中のMETA-INF/springディレクトリ配下のpropertiesファイルを読み込む。一度設定すれば、あとはMETA-INF/spring以下にpropertiesファイルを追加するだけで良い。locationの設定値の詳細は、Spring Framework Documentation -Resources-を参照されたい。Note
<context:property-placeholder>
の定義は、applicationContext.xml
とspring-mvc.xml
の両方に定義が必要である。
デフォルトでは、以下の順番でプロパティにアクセスする。
- 実行中のJVMのシステムプロパティ
- 環境変数
- アプリケーション定義のプロパティファイル
<context:property-placeholder/>
タグのlocal-override属性をtrueに設定する。bean定義ファイル
<context:property-placeholder location="classpath*:META-INF/spring/*.properties" local-override="true" /> <!-- (1) -->
項番 説明 (1) local-override属性をtrueに設定すると、以下の順番でプロパティにアクセスする。1. アプリケーション定義のプロパティ2. 実行中のJVMのシステムプロパティ3. 環境変数Note
通常は上記の設定で十分である。
複数の
<context:property-placeholder/>
タグを指定する場合、order属性の値を設定することで、読み込みの順位付けをすることができる。bean定義ファイル
<context:property-placeholder location="classpath:/META-INF/property/extendPropertySources.properties" order="1" ignore-unresolvable="true" /> <!-- (1) --> <context:property-placeholder location="classpath*:/META-INF/spring/*.properties" order="2" ignore-unresolvable="true" /> <!-- (2) -->
項番 説明 (1) order属性を(2)より低い値を設定することにより、(2)より先にlocation属性に該当するプロパティファイルが読み込まれる。(2)で読み込んだプロパティファイル内のキーと重複するキーが存在する場合、(1)で取得した値が優先される。ignore-unresolvable属性をtrueにすることで、(2)のプロパティファイルのみにキーが存在する場合にエラーが発生するのを防ぐ。 (2) order属性を(1)より高い値を設定することにより、(1)の次にlocation属性に該当するプロパティファイルが読み込まれる。(1)で読み込んだプロパティファイル内のキーと重複するキーが存在する場合、(1)で取得した値が設定される。ignore-unresolvable属性をtrueにすることで、(1)のプロパティファイルのみにキーが存在する場合にエラーが発生するのを防ぐ。
7.2.2.2. bean定義ファイル内でプロパティを使用する¶
<context:property-placeholder/>
)が指定されている前提で行う。${}
プレースホルダで設定することで、プロパティ値を設定することができる。プロパティファイル
database.url=jdbc:postgresql://localhost:5432/shopping database.password=postgres database.username=postgres database.driverClassName=org.postgresql.Driver
bean定義ファイル
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="${database.driverClassName}"/> <!-- (1) --> <property name="url" value="${database.url}"/> <!-- (2) --> <property name="username" value="${database.username}"/> <!-- (3) --> <property name="password" value="${database.password}"/> <!-- (4) --> <!-- omitted --> </bean>
項番 説明 (1)${database.driverClassName}
を設定することで、読み込まれたプロパティファイルのキーdatabase.driverClassName
に対する値が代入される。 (2)${database.url}
を設定することで、読み込まれたプロパティファイルのキーdatabase.url
に対する値が代入される。 (3)${database.username}
を設定することで、読み込まれたプロパティファイルのキーdatabase.username
に対する値が代入される。 (4)${database.password}
を設定することで、読み込まれたプロパティファイルのキーdatabase.password
に対する値が代入される。
propertiesファイルのキーが読み込まれた結果、以下のように置換される。
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="org.postgresql.Driver"/> <property name="url" value="jdbc:postgresql://localhost:5432/shopping"/> <property name="username" value="postgres"/> <property name="password" value="postgres"/> <!-- omitted --> </bean>
7.2.2.3. Javaクラス内でプロパティを使用する¶
@Value
アノテーションを指定することで実現できる。@Value
アノテーションを使用するためには、そのオブジェクトはSpringのDIコンテナに管理されている必要がある。<context:property-placeholder/>
)が指定されている前提で行う。@Value
アノテーションを付与し、valueにpropetyファイルのキーを${}
プレースホルダで設定することで外部参照することができる。プロパティファイル
item.upload.title=list of update file item.upload.dir=file:/tmp/upload item.upload.maxUpdateFileNum=10
Javaクラス
@Value("${item.upload.title}") // (1) private String uploadTitle; @Value("${item.upload.dir}") // (2) private Resource uploadDir; @Value("${item.upload.maxUpdateFileNum}") // (3) private int maxUpdateFileNum; // Getters and setters omitted
項番 説明 (1)@Value
アノテーションのvalueに${item.upload.title}
を設定することで、読み込まれたプロパティファイルのキーitem.upload.title
に対する値が代入される。uploadTitle
にはStringクラスに”list of update file”が代入される。 (2)@Value
アノテーションのvalueに${item.upload.dir}
を設定することで、読み込まれたプロパティファイルのキーitem.upload.dir
に対する値が代入される。uploadDir
には初期値”/tmp/upload”でオブジェクト生成されたorg.springframework.core.io.Resource
オブジェクトが格納される。 (3)@Value
アノテーションのvalueに${item.upload.maxUpdateFileNum}
を設定することで、読み込まれたプロパティファイルのキーitem.upload.maxUpdateFileNum
に対する値が代入される。maxUpdateFileNum
には整数型に10が代入される。Warning
Utilityクラスなどのstaticメソッドからプロパティ値を利用したい場合も考えられるが、Bean定義されないクラスでは
@Value
アノテーションによるプロパティ値の取得は行えない。このような場合には、
@Component
アノテーションを付けたHelperクラスを作成し、@Value
アノテーションでプロパティ値を取得することを推奨する。(当然、該当クラスはcomponent-scanの対象にする必要がある。)プロパティ値を利用したいクラスは、Utilityクラスにすべきでない。
7.2.3. How to extend¶
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
クラスを拡張することで実現できる。拡張例として、暗号化したプロパティファイルを使用するケースを挙げる。
7.2.3.1. 暗号化したプロパティ値を復号して使用する¶
Bean定義ファイル
applicationContext.xml
spring-mvc.xml
<!-- (1) --> <bean class="com.example.common.property.EncryptedPropertySourcesPlaceholderConfigurer"> <!-- (2) --> <property name="locations" value="classpath*:/META-INF/spring/*.properties" /> </bean>
項番 説明 (1)<context:property-placeholder/>
の代わりに拡張したPropertySourcesPlaceholderConfigurerを定義する。<context:property-placeholder/>
タグを削除しておくこと。(2)propertyタグのname属性に”locations”を設定し、value属性に読み込むプロパティファイルパスを指定する。読み込むプロパティファイルパスの指定方法はプロパティファイル定義方法についてと同じ。
Javaクラス
拡張したPropertySourcesPlaceholderConfigurer
public class EncryptedPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer { // (1) @Override protected void doProcessProperties( ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { // (2) super.doProcessProperties(beanFactoryToProcess, new EncryptedValueResolver(valueResolver)); // (3) } }
項番 説明 (1)拡張したPropertySourcesPlaceholderConfigurerはorg.springframework.context.support.PropertySourcesPlaceholderConfigurer
をextendする。(2)org.springframework.context.support.PropertySourcesPlaceholderConfigurer
クラスのdoProcessProperties
メソッドをoverrideする。(3)親クラスのdoProcessProperties
を呼び出すが、valueResolver
は独自実装したvalueResolver(EncryptedValueResolver
)を使用する。EncryptedValueResolver
クラス内で、プロパティファイルの暗号化されたvalueを取得した場合に復号する。
EncryptedValueResolver.java
public class EncryptedValueResolver implements StringValueResolver { // (1) private final StringValueResolver valueResolver; EncryptedValueResolver(StringValueResolver stringValueResolver) { // (2) this.valueResolver = stringValueResolver; } @Override public String resolveStringValue(String strVal) { // (3) // Values obtained from the property file to the naming // as seen with the encryption target String value = valueResolver.resolveStringValue(strVal); // (4) // Target messages only, implement coding if (value.startsWith("Encrypted:")) { // (5) value = value.substring(10); // (6) // omitted decryption } return value; } }
項番 説明 (1)拡張したEncryptedValueResolver
は、org.springframework.util.StringValueResolver
を実装する。(2)コンストラクタでEncryptedValueResolver
クラスを生成したときに、EncryptedPropertySourcesPlaceholderConfigurer
から引き継いできたStringValueResolver
を設定する。(3)org.springframework.util.StringValueResolver
のresolveStringValue
メソッドをovewrideする。resolveStringValue
メソッド内にて、プロパティファイルの暗号化されたvalueを取得した場合に復号する。以降、(5)~(6)は一例の処理になるため、実装によって処理が異なる。(4)コンストラクタで設定したStringValueResolver
のresolveStringValue
メソッドの引数にキーを指定して値を取得している。この値は実際にプロパティファイルに定義されている値である。(5)プロパティファイルの値が暗号化された値かどうかをチェックする。判定方法については実装によって異なる。ここでは値が”Encrypted:”から始まるかどうかで、暗号化されているかどうかを判断する。暗号化されている場合、(6)で復号を実施し、暗号化されていない場合、そのままの値を返却する。(6)プロパティファイルの暗号化されたvalueの復号を行っている。(具体的な復号処理については省略する。)復号の方法については実装によって異なる。
プロパティを取得するHelper
@Value("${encrypted.property.string}") // (1) private String testString; @Value("${encrypted.property.int}") // (2) private int testInt; @Value("${encrypted.property.integer}") // (3) private Integer testInteger; @Value("${encrypted.property.file}") // (4) private File testFile; // Getters and setters omitted
項番 説明 (1)@Value
アノテーションのvalueに${encrypted.property.string}
を設定することで、読み込まれたプロパティファイルのキーencrypted.property.string
に対する値が復号されて代入される。testString
にはStringクラスに復号された値が代入される。(2)@Value
アノテーションのvalueに${encrypted.property.int}
を設定することで、読み込まれたプロパティファイルのキーencrypted.property.int
に対する値が復号されて代入される。testInt
には整数型に復号された値が代入される。(3)@Value
アノテーションのvalueに${encrypted.property.integer}
を設定することで、読み込まれたプロパティファイルのキーencrypted.property.integer
に対する値が復号されて代入される。testInteger
にはIntegerクラスに復号された値が代入される。(4)@Value
アノテーションのvalueに${encrypted.property.file}
を設定することで、読み込まれたプロパティファイルのキーencrypted.property.file
に対する値が復号されて代入される。testFile
には初期値に復号された値でオブジェクト生成されたFileオブジェクトが格納される。(自動変換)
プロパティファイル
encrypted.property.string=Encrypted:ZlpbQRJRWlNAU1FGV0ASRVteXhJQVxJXXFFAS0JGV1Yc
encrypted.property.int=Encrypted:AwI=
encrypted.property.integer=Encrypted:AwICAgI=
encrypted.property.file=Encrypted:YkBdQldARkt/U1xTVVdfV1xGHFpGX14=