山崎屋の技術メモ

IT業界で働く中で、気になること、メモしておきたいことを書いていきます。

【Spring Framework】プロパティファイルを読む②

f:id:yyama1556:20160812103358p:plain

前回の記事では[PropertiesFactoryBean]を使ったプロパティの取得方法を紹介した。今回は、もうひとつのやり方である[property-placeholder]を使用したプロパティの使用方法を紹介する。

SpringMVCでこれを使用する際の注意点として、[property-placeholder]はapplicationContext.xml と spring-mvc.xml の両方に定義が必要である。

ソース

フォルダ構成。
f:id:yyama1556:20160812103644p:plain

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="org.yyama.hoge" />
	<context:property-placeholder location="classpath*:myProp.properties" />
</beans>

[context:property-placeholder]を使用している。要素[location]にはプロパティファイルの位置を指定する。サンプルではClassPath直下の"myProp.properties"を指定している。

プロパティファイル"myProp.properties"は前回と一緒。

key=value

次にFugaクラス。

package org.yyama.hoge;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Fuga {

	@Value("${key}")
	String value;

	public void proc() throws Exception {
		System.out.println("key:" + value);
	}
}

[@Value("${key}")]でプロパティファイルを読み込み、keyに紐づく値を変数"value"に設定してくれる。このように${キーの値}という書き方でvalueを取得できると覚えておく。

キーが見つからない場合、次のような例外が発生する。

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fuga': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'key' in string value "${key}"
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:355)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:776)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
	at org.yyama.Main.main(Main.java:8)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'key' in string value "${key}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
	... 13 more

続いてMainクラス。前回のサンプルと同じ。

package org.yyama;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.yyama.hoge.Fuga;

public class Main {
	public static void main(String... args) throws Exception {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		ctx.getBean(Fuga.class).proc();
		ctx.close();
	}
}

一応pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>Sample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<!-- Generic properties -->
		<java.version>1.8</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<!-- Spring -->
		<spring-framework.version>4.3.2.RELEASE</spring-framework.version>
	</properties>
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
	</dependencies>
</project>

実行すると以下の出力が得られ、プロパティファイルが正しく読み込まれていることが確認できる。

key:value

設定ファイル内でも使えるよ

[property-placeholder]で取得したプロパティの値はSpringの設定ファイル内でも使用できる。このサンプルでいう[applicationContext.xml]ファイル内で使用できる。

たとえば次のような感じ。

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="org.yyama.hoge" />
	<context:property-placeholder location="classpath*:myProp.properties" />
	<bean class="org.yyama.hoge.Piyo">
		<property name="val" value="${key}" />
	</bean>
</beans>

propertyタグのvalue要素に"${key}"と記載されている。これでPiyoクラスの変数valにプロパティファイルで定義されているkeyに紐づく値が自動でセットされる。

Piyoクラス。

package org.yyama.hoge;

public class Piyo {
	String val;

	public void setVal(String val) {
		this.val = val;
	}

	public void proc() throws Exception {
		System.out.println("key:" + val);
	}
}

本題とは関係ないが、変数に値を自動セットしたい場合はsetterは必要になる。

まとめ

2回にわたり[PropertiesFactoryBean]と[context:property-placeholde]でプロパティファイルを読み込むサンプルを示した。どちらを使ってもいいと思うが、設定ファイル内でプロパティファイルの内容を利用できる点で[context:property-placeholde]に軍配が上がるのではないだろうか。


Spring 関連記事へのリンク集つくりました。