Java

Spring MVCの設定ファイル読み込みでファイル名を動的かつ複数設定する方法

2020年11月13日

このページに書いてあること

Spring MVCで設定ファイルを読み込むときに、条件に応じて使用する設定情報を使い分けたい場合があります。
例えば、社内環境用のアプリと社外環境用のアプリ(以降、内部と外部)が同インスタンスにしており、経路によって使用する設定を切り替えたい場合です。内部と外部で設定ファイル名を分けてapplication_intra.properties/application_internet.propertiesを読み込みたい場合ですね。

そんな時は、PathMatchingResourcePatternResolverを使うとできる可能性があります。

前提

  • SpringMVCのバージョンは5.1.19.RELEASE
  • application_intra.properties/application_internet.propertiesで個別のクラスを作りたくない(設定ファイルが追加されたら大変)

一般的な設定ファイル読み込み

Spring MVCではいくつかの設定ファイル読み込み方法があるのですが、一般的なものはアノテーションによるものだと思います。

@Configuration
@PropertySource("classpath:application.properties")

@Configurationにより起動時の設定処理であることを通知し、起動時に実行してもらいます。
@PropertySourceにより読み込む設定ファイルを指定しています。("classpath:application.properties")の記述は、クラスパス配下からapplication.propertiesの名前に一致するファイルを読み込む設定です。

で、このときの問題が読み込む設定ファイルをこの書き方は設定ファイル名が固定ということです。
外部向けインスタンスと内部向けインスタンスを作りたい場合、ここの記述を変えないといけないということになります。

こちらの期待としては、ワイルドカードなどを使って全部読み込んでほしいところです。

@PropertySource("classpath:application_*.properties")

残念ですがこれは使えません。仕組み上ここでは1個のファイルしか設定できないのでワイルドカードで複数指定が不可能です。

複数のファイルを読み込むことも可能です。Springの4以降で使用できる@PropertySourcesを使います。

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:another.properties")
})

ただ、見ての通りでこちらは設定ファイル名をベタ書きする必要があるので、今後設定ファイルが増えていくとキツイです。

PathMatchingResourcePatternResolverによる読み込み

アノテーションでの実施をあきらめて、Javaコード内で吸収しようという話です。

org.springframework.core.io.support.PathMatchingResourcePatternResolver.PathMatchingResourcePatternResolver()

を使って、好きな名前のファイルをJavaコード内で指定することで読み込みを行います。

こんな感じです。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;

import javax.servlet.ServletContext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import lombok.AllArgsConstructor;

@Configuration
@AllArgsConstructor
public class Config {

	@Bean
	public void config() throws IOException {

		Resource[] resources = new PathMatchingResourcePatternResolver().getResources(
				"classpath:application_*.properties");

		Properties properties = new Properties();
		for (Resource resource : resources) {
			properties.load(new InputStreamReader(new FileInputStream(
					resource.getFile()), "UTF-8"));
		}
	}
}

この例では、

"classpath:application_*.properties"

という記述により例えば、application_intra.propertiesやapplication_internet.propertiesなどの名前をひっかけることができます。
クラスパス配下にapplication_intra2.propertiesが追加されればそれもロードすることができます。

重要なのは、この方式であれば正規表現による探索が可能ということ、対象はクラスパス配下に限るという所でしょうか。

ファイル名を何らかのルールに基づいて動的に決めたい場合はこのようにするといいかもしれません。

###############お知らせ################
ブログランキングのITカテゴリに参加してみました。
この記事が役に立ったなどお力になれたら、 このバナーを押していただけると嬉しいです。

#####################################

-Java