プロパティファイルを扱うためのクラス群はcoreやcontextなどに含まれている。そのためSpringの基本的なjarだけあればよい。Springに必要なjarについてはSpringの導入&サンプルプログラムを参照。
プロパティファイルを読み込むためには以下2つの方法がある。
それぞれ一言で説明するのが難しいが、大雑把に言うとEnviromentはマップのようにキーからプロパティ値を取得できる。PlaceholderはBeanの各フィールドにプロパティキーを紐づけることにより取得できる。
なお、どちらも機能的な縛りがあるため、実装の自由度を求めるのであれば、Java標準のPropertiesクラスを使用した方が無難かもしれない。
まずはEnvironmentを利用する方法。以下の手順で実施する。
読み込むプロパティファイルを用意する。
spring.test=test
プロパティを読み込むJavaのクラスを作成する。
package proptest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
// ①クラス宣言に@Configurationと@PropertySourceを付加
@Configuration
@PropertySource("classpath:/proptest/app.properties")
public class MyProperty{
// ②Environmentをインジェクション
@Autowired
private Environment env;
public String get(String key){
// ③Environmentからプロパティ値を取得
return env.getProperty(key);
}
}
[説明]
①クラス宣言に@Configurationと@PropertySourceを付加
@Configuration
@PropertySource("classpath:/proptest/app.properties")
public class MyProperty{
クラス宣言の上部に@Configurationと@PropertySourceアノテーションを付ける。
@PropertySourceにはプロパティファイル名をパス付で指定する。クラスパスから取得する場合は「classpath:~」と記述、物理パスから取得する場合は「file:~」と記述する。
・複数ファイル読み込む場合
下記のようにファイルを羅列することで、複数ファイルを読み込むことができる。中身はマージされ、後に記述したもので上書きされる。@PropertySource({"classpath:/proptest/app.properties", "classpath:/proptest/app2.properties"})
・プロパティファイルが存在しない場合
読み込むプロパティファイルが存在しない場合、デフォルトでは例外が発生する。例外を無視したいときは「ignoreResourceNotFound=true」を指定する。(@PropertySourceでパラメータを2つ以上書く場合は、key=value形式にする)
@PropertySource(value="classpath:/proptest/app.properties", ignoreResourceNotFound=true)
・パスやファイル名を動的に変更したい場合
プロパティファイルのパスやファイル名を動的に変更したい場合、プレースホルダを使用する。${}形式で記述した箇所が、システムプロパティあるいは環境変数で設定した値に置換される。 システムプロパティと環境変数の両方で指定された場合は、システムプロパティの値が優先される。
@PropertySource("classpath:${PROP_PATH}/app.properties")
②Environmentをインジェクション
@Autowired
private Environment env;
@AutowiredでEnvironmentのインスタンスを取得する。
Environmentはプロパティの値を保持するクラス(正確にはインタフェース)。Environmentからマップ形式でプロパティの値が取得できる。
- Environmentを使用する上での注意点 -
Environmentはプロパティファイルの値だけでなく、システムプロパティと環境変数の値も一緒に保持している。 同じキーが存在した場合の優先順位は①システムプロパティ、②環境変数、③プロパティファイルとなっており、プロパティファイルと同じキーがシステムプロパティや環境変数に存在すると値が上書きされてしまうので注意。
またEnvironmentはSpring管理下でインスタンスが1つに限定されるため、仮にサンプルのMyProperty.javaを複製して異なるプロパティファイルを読み込むクラスMyProperty2.javaを作ったとしても、プロパティを保持するのは同じEnvironmentインスタンスとなる。従って、異なるプロパティファイルに同じキーが存在すると、どちらかに上書きされてしまう。
③Environmentからプロパティ値を取得
return env.getProperty(key);
EnvironmentのgetPropertyメソッドを使用してプロパティの値を取得する。
作成したMyPropertyクラスの検証用にmainのJavaクラスを作成する。
package proptest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringSample {
// ①MyPropertyをインジェクション
@Autowired
private MyProperty myProp;
public static void main(String[] args){
ApplicationContext context =
new ClassPathXmlApplicationContext("ApplicationContext.xml");
SpringSample ss = context.getBean(SpringSample.class);
ss.out();
}
public void out(){
// ②MyPropertyからプロパティ値を取得して出力
String value = myProp.get("spring.test");
System.out.println("spring.test=" + value);
}
}
[説明]
①MyPropertyをインジェクション
@Autowired
private MyProperty myProp
@Autowiredで先ほど作成したMyPropertyクラスのインスタンスを取得する。
②MyPropertyからプロパティ値を取得して出力
String value = myProp.get("spring.test");
System.out.println("spring.test=" + value);
MyPropertyのgetメソッドでプロパティ値を出力
spring.test=test
app.propertiesの「spring.test」の値が出力される。
次にPlaceholderを利用する方法。以下の手順で実施する。
読み込むプロパティファイルを用意する。
app.user.id=001
app.user.name=John
Spring設定ファイルにも1行追加する。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="proptest" />
<!-- ①プロパティファイルの読み込み -->
<context:property-placeholder location="classpath:/proptest/app.properties"/>
</beans>
[説明]
①プロパティファイルの読み込み
Spring設定ファイルに<context:property-placeholder>を記述し、location属性にプロパティファイル名を設定する。location属性の書き方は前述の@PropertySourceのパラメータと同じ。これだけでプロパティファイルのプロパティ値が使えるようになる。
プロパティ値を格納するAppPropertyBeanクラスを作成する。
package proptest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppPropertyBean {
// ①@Valueでプロパティキーと変数を紐づけ
@Value("${app.user.id}")
private String id;
@Value("${app.user.name}")
private String name;
// ②getterを用意
public String getId(){
return id;
}
public String getName(){
return name;
}
}
[説明]
①@Valueでプロパティキーと変数を紐づけ
@Value("${app.user.id}")
private String id;
@Valueアノテーションにプロパティのキー名を指定すると、変数にそのプロパティの値が格納される。Springでは、この${}形式をプレースホルダと呼ぶ。
プレースホルダもEnvironmentと同じくシステムプロパティと環境変数からも値が取得される。優先順位も同じで①システムプロパティ、②環境変数、③プロパティファイルとなっているが、 プレースホルダの場合、<context:property-placeholder>のlocal-override属性を「true」にすることで、プロパティファイルを最優先にすることができる。
<context:property-placeholder location="classpath:/proptest/app.properties" local-override="true"/>
②getterを用意
public String getId(){
return id;
}
一般的にはプロパティ値を返却するgetterを用意する。
作成したAppPropertyBeanクラスの検証用にmainのJavaクラスを作成する。
package proptest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class SpringSample {
// ①Beanクラスをインジェクション
@Autowired
private AppPropertyBean propBean;
public static void main(String[] args){
ApplicationContext context =
new ClassPathXmlApplicationContext("ApplicationContext8.xml");
SpringSample ss = context.getBean(SpringSample.class);
ss.out();
}
public void out(){
// ②Beanクラスからプロパティ値を取得して出力
String id = propBean.getId();
String name = propBean.getName();
System.out.println("id=" + id + ", name=" + name);
}
}
[説明]
①Beanクラスをインジェクション
@Autowired
private AppPropertyBean propBean;
②Beanクラスからプロパティ値を取得して出力
String id = propBean.getId();
String name = propBean.getName();
System.out.println("id=" + id + ", name=" + name);
app.propertiesの「app.user.id」と「app.user.name」の値が出力される。
id=001, name=John
プレースホルダは以下のようにSpring設定ファイル内でも使用できる。
classname=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/sampledb
username=testuser
password=testpassword
ApplicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="proptest" />
<context:property-placeholder location="classpath:/proptest/app.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="${classname}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<bean class="test.SampleDao">
<property name="JdbcTemplate" ref="jdbcTemplate" />
</bean>
</beans>