TIL

Today I Learned. 知ったこと、学んだことを書いていく

【Java】Spring Bootで Java Config を使用し、Propertiesファイルを読み込む

SpringBootを使って、Propertiesファイルを読みたかったから、やってみた

XML書きたくないから、Java Configで実装した

以下の2つのJavaクラスを作った

  • sample/App.java
  • sample/config/Config.java

sample/config/Config.java

package sample.config;

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

import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableAutoConfiguration
public class Config {

    @Bean
    public Properties sqlProperties() throws IOException {

        PropertiesFactoryBean propFactoryBean = new PropertiesFactoryBean();
        propFactoryBean.setLocation(new ClassPathResource("sample.properties"));
        // これ大事!
        propFactoryBean.afterPropertiesSet();
        return propFactoryBean.getObject();

    }
}
  • Propertiesを返すBeanを定義
  • Propertiesを生成するためのPropertiesFactoryBeanを用意
    • locationClassPathResourceインスタンスをセット
      • src/main/resources/sample.propertiesだとしたら、new ClassPathResource('sample.properties')とする
      • SpringBootでsrc/main/resourcesはクラスパス内のため
    • PropertiesFactoryBean.afterPropertiesSet()がないとうまく値を取れなかったため、必ず実行すること
      • 何をしているのかはよくわからない
  • PropertiesFactoryBean.getObject()でPropertiesのインスタンスを返す

sample/App.java

package sample;

import java.util.Properties;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;


@SpringBootApplication
public class App
{
    private static final Logger log = LoggerFactory.getLogger(App.class);

    @Resource
    private Properties sqlProperties;

    public static void main(String[] args) {
        log.info("Hello World!");
        try(ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args)) {
            App app = ctx.getBean(App.class);
            app.run(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run(String... args) throws Exception {

        log.info(sqlProperties.getProperty("samplevalue"));

    }
}
  • DIしたいProperties型の変数に@Resourceをつける
    • @ResourceはBean名でDIされるらしい
      • 今回の場合、sqlProperties
  • getProperty()で取得

src/main/resources/sample.properties

samplevalue=hello world

実行

20:30:49.252 [main] INFO sample.App - Hello World!

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.6.RELEASE)

2019-07-22 20:30:49.827  INFO 42668 --- [           main] sample.App                               : Starting App on Plus-OP021 with PID 42668 (C:\pleiades\workspace\spring-boot-properties-load\target\classes started by t-ohsaka in C:\pleiades\workspace\spring-boot-properties-load)
2019-07-22 20:30:49.828  INFO 42668 --- [           main] sample.App                               : No active profile set, falling back to default profiles: default
2019-07-22 20:30:50.507  INFO 42668 --- [           main] sample.App                               : Started App in 1.052 seconds (JVM running for 1.604)
2019-07-22 20:30:50.510  INFO 42668 --- [           main] sample.App                               : hello world!

わーできた!!簡単!!

今回のプロジェクトはここ に置いた


エラーが出たときのメモ

  • Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'java.util.Properties' available: expected single matching bean but found 2: sqlProperties,systemProperties
    • SpringのDIは型で一致したものをDIするため、同じ型のものがあると、どっちかわからない
    • @Resourceで変数名を@Beanをつけたメソッド名と同じにする
  • Bean named 'sqlProperties' is expected to be of type 'java.util.Properties' but was actually of type 'org.springframework.beans.factory.support.NullBean'
    • 正しく@Beanで返せていなかった
    • PropertiesFactoryBean.afterPropertiesSet()を実行する
      • SpringのDIコンテナはbeanを生成しプロパティがセットされた後にafterPropertiesSet()メソッドを呼び出します
      • 5.DIされたときの動作の制御(カスタマイズ)について - soracane
      • JavaDocの和訳
        • すべてのBeanプロパティを設定し、BeanFactoryAware、ApplicationContextAwareなどを満たした後で、格納されているBeanFactoryによって呼び出されます。

        • このメソッドを使用すると、Beanインスタンスは、すべてのBeanプロパティが設定されたときに、全体の構成の検証と最終的な初期化を実行できます。

        • んーわからん

参考文献