YAMLを使用したSpring @PropertySource


107

Spring Bootを使用すると、application.propertiesファイルを同等のYAMLに置き換えることができます。しかし、私は私のテストで障害にぶつかったようです。私TestConfiguration(簡単なJava設定)に注釈を付けると、プロパティファイルが必要になります。

たとえば、これは機能しません: @PropertySource(value = "classpath:application-test.yml")

YAMLファイルにこれがある場合:

db:
  url: jdbc:oracle:thin:@pathToMyDb
  username: someUser
  password: fakePassword

そして、私はこれらの値を次のようなもので活用します:

@Value("${db.username}") String username

しかし、私はそのようにエラーになってしまいます:

Could not resolve placeholder 'db.username' in string value "${db.username}"

テストでもYAMLの良さを活用するにはどうすればよいですか?


「機能しない」を定義します。例外/エラー/警告は何ですか?
Emerson Farrugia 2014年

Spring BootはYAMLファイルをフラット化するため、ドット表記のプロパティファイルとして表示されます。その平坦化は起こっていません。
checketts 2014年

そして確認のために、これは非テストコードで機能しますか?
Emerson Farrugia 2014年

1
はい。ここに、projects.spring.io / spring-boot / docs / spring-boot-actuator /…を説明するドキュメントがあり、ページの下の方に「YAMLオブジェクトはピリオド区切り文字を使用してフラット化されていることに注意してください」と書かれています。
checketts 2014年

9
SpingBootは、PropertySourceを使用してYAMLをロードできないと述べています:24.6.4 YAMLの欠点YAMLファイルは@PropertySourceアノテーションを介してロードできません。したがって、この方法で値をロードする必要がある場合は、プロパティファイルを使用する必要があります。
Lex Pro

回答:


54

Spring-bootにはこれのためのヘルパーがあり、追加するだけです

@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)

テストクラスまたは抽象テストスーパークラスの上部。

編集:私は5年前にこの回答を書きました。Spring Bootの最近のバージョンでは動作しません。これが私が今行っていることです(必要に応じてKotlinをJavaに翻訳してください)。

@TestPropertySource(locations=["classpath:application.yml"])
@ContextConfiguration(
        initializers=[ConfigFileApplicationContextInitializer::class]
)

上に追加され、

    @Configuration
    open class TestConfig {

        @Bean
        open fun propertiesResolver(): PropertySourcesPlaceholderConfigurer {
            return PropertySourcesPlaceholderConfigurer()
        }
    }

コンテキストに。


3
PropertySourcesPlaceholderConfigurerを忘れないでください
Kalpesh Soni

@KalpeshSoniは確かに、Configuratorがないと機能しません。
Ola Sundell

代わりに、@ SpringJunitConfigに初期化子を追加する必要がありました@SpringJUnitConfig(value = {...}, initializers = {ConfigFileApplicationContextInitializer.class})
Tomas F

1
@Jan Galinskiあなたは私の答えを試すことができます、それは使いやすいです、そしてそれは私の製品環境でうまく機能します。stackoverflow.com/questions/21271468/...
Forest10

59

それが言及されたように、@PropertySourceyamlファイルをロードしません。回避策として、自分でファイルをロードし、ロードしたプロパティをに追加しますEnvironment

実装ApplicationContextInitializer

public class YamlFileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    try {
        Resource resource = applicationContext.getResource("classpath:file.yml");
        YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
        PropertySource<?> yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null);
        applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
  }
}

テストにイニシャライザを追加します。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class)
public class SimpleTest {
  @Test
  public test(){
    // test your properties
  }
}

実際にはこれが最善の答えになるはずです、それはうまくいきました!
アデリン2016年

Mateusz、私はYamlFileApplicationContextInitializerYAMLの場所がテストケースごとに定義されるクラスで回答を投稿しました。面白いと思ったら、お気軽に回答に差し込んでください。削除します。私の答えの下のコメントで知らせてください。
Michal Foksa

はい、これが最良の答えです
リチャードHM

34

@PropertySourcefactory引数で設定できます。だからあなたは次のようなことをすることができます:

@PropertySource(value = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class)

YamlPropertyLoaderFactoryカスタムプロパティローダーはどこにありますか。

public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        if (resource == null){
            return super.createPropertySource(name, resource);
        }

        return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null);
    }
}

https://stackoverflow.com/a/45882447/4527110に触発されました


2
この基礎となるYAMLの解析はスローIllegalStateExceptionファイルではなく、適切で存在しない場合FileNotFoundException-そうで、この作品を作るために@PropertySource(..., ignoreResourceNotFound = true)、あなたはこのケースをキャッチする必要があり、処理します: try { return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null); } catch (IllegalStateException e) { throw (IOException) e.getCause(); }
クリスチャン・オピッツ

2
特定のプロファイルのプロパティを取得する必要がある場合、YamlPropertySourceLoader.load()の3番目のパラメーターはプロファイル名です。YamlPropertySourceLoader.load()は、単一のプロパティソースではなくリストを返すように変更されました。詳細はこちらstackoverflow.com/a/53697551/10668441
pcoates 2018

1
これはこれまでで最もクリーンなアプローチです。
Michal Foksa

7
私にとっては、次のように見返りに少し変更する必要がありましたCompositePropertySource propertySource = new CompositePropertySource(name); new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource()).stream().forEach(propertySource::addPropertySource); return propertySource;
。– xorcus

28

@PropertySourceプロパティファイルのみをサポートします(これはSpringからの制限であり、Boot自体ではありません)。JIRAで機能リクエストチケット自由に開いてください。


テスト構成に渡すことができる環境で、yamlリスナーを再利用する方法、または手動でyamlをロードする方法があるといいのですが。
checketts 2014年

10
私はあなたがを書いてApplicationContextInitializer、それをテスト構成に追加できると思います(単にを使用してYamlPropertySourceLoaderを拡張しますEnvironment)。個人的には、@PropertySourceこの振る舞いをネイティブでサポートするのが望ましいです。
Dave Syer 2014年

これはまだ事実ですか?'@PropertySource'はYAMLをサポートしていませんか?
domi

1
stackoverflow.com/questions/21271468/… これを使用して解決できる@PropertySourceはプロパティファイルのみをサポート
Forest10

この6歳の投稿で自分の問題を解決したことにショックを受けました。
ジンクォン・

20

別のオプションはspring.config.locationthrough を設定すること@TestPropertySourceです:

@TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }

3
私は次の行で入力をパラメーター化しました: @TestPropertySource(properties = {"spring.config.location=classpath:application-${test.env}.yml" }) IMO yoursがすべての中で最良の答えです。
leventunver

1
素晴らしいアイデアとテストのための非常に最小限のこと、ありがとうございました!:だけがあたり、1は、複数の設定ファイルを含めることができ、追加する@TestPropertySource(properties = {"spring.config.location=classpath:application-config.yml,classpath:test-config.yml,..." })
STX

1
これは断然最高の答えです!@SpringBootTest注釈が必要であることに注意してください
Mistriel

魔法のように動作します!
user1079877

19

Spring Boot 1.4から、@SpringBootTestSpring Bootサポートを使用して統合テストをブートストラップすることで、新しいアノテーションを使用してこれをより簡単に(そして統合テストのセットアップを一般的に簡素化)することができます。

春ブログの詳細。

私の知る限り、これは、クラスパスからYAML構成を自動的に取得することを含め、運用コードと同じように、Spring Bootの外部化された構成の利点をすべて活用できることを意味します。

デフォルトでは、この注釈は

...最初に@Configuration内部クラスからロードを試み、それが失敗した場合は、プライマリ@SpringBootApplicationクラスを検索します。

ただし、必要に応じて他の構成クラスを指定できます。

この特定のケースでは、と組み合わせ@SpringBootTest@ActiveProfiles( "test" )、SpringがYAML構成を取得します。ただし、それが通常のブート命名標準(つまりapplication-test.yml)に準拠している必要があります。

@RunWith( SpringRunner.class )
@SpringBootTest
@ActiveProfiles( "test" )
public class SpringBootITest {

    @Value("${db.username}")
    private String username;

    @Autowired
    private MyBean myBean;

    ...

}

注:SpringRunner.classはの新しい名前ですSpringJUnit4ClassRunner.class


1
:) @ActiveProfilesの使用は、機能した唯一のオプションです。ありがとう!
zcourts

10

yamlプロパティをロードするアプローチであるIMHOは、次の2つの方法で実行できます。

a。構成を標準の場所(application.ymlクラスsrc/main/resourcesパスルート)に配置できます。通常、このyamlプロパティは、言及したフラット化されたパス名でSpringブートによって自動的に読み込まれます。

b。2番目のアプローチはもう少し広範で、基本的には次のようにプロパティを保持するクラスを定義します。

@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties {
    private String url;
    private String username;
    private String password;
...
}

つまり、本質的には、yamlファイルをロードして、「db」のルート要素に基づいてDbPropertiesクラスにデータを投入するということです。

これを任意のクラスで使用するには、次のようにする必要があります。

@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {

    @Autowired private DbProperties dbProperties;

}

これらのアプローチはどちらも、Spring-bootを使用して問題なく機能するはずです。


クラスパスにsnakeymlがあり、上記が機能することを確認してください。
2014年

3
最近では(この質問が尋ねられたときではありませんが)、snakeyamlによって推移的な依存関係として取り込まれているため、別のバージョンを使用したいという根強い衝動がない限りspring-boot-starterpom.xmlor に追加する必要はありませんbuild.gradle。:)
Steve

2
現在locationsではなくpathであり、これConfigFileApplicationContextInitializerも必須です。
OrangeDog

3

@ActiveProfiles("test")application-test.ymlファイルを使用してsrc / test / resourcesに追加することで回避策を見つけました。

最終的には次のようになります。

@SpringApplicationConfiguration(classes = Application.class, initializers = ConfigFileApplicationContextInitializer.class)
@ActiveProfiles("test")
public abstract class AbstractIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests {

}

application-test.ymlファイルには、application.ymlからオーバーライドするプロパティ(src / main / resourcesにあります)のみが含まれています。


これも私が使おうとしていたものです。何らかの理由で使用すると機能しません(Spring Boot 1.3.3)が、を使用すると問題@Value("${my.property}")なく動作しますenvironment.getProperty("my.property")
martin-g

1

snakeymlを設定していないからです。スプリングブートには@EnableAutoConfiguration機能が付属しています。このアノテーションを呼び出すと、snakeyml設定も表示されます。

これが私のやり方です:

@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}

これが私のテストです:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
        classes = {
                AppContextTest.class,
                JaxbConfiguration.class,
        }
)

public class JaxbTest {
//tests are ommited
}

0

コードにいくつかのプロパティを読み込む必要があり、これはspring-boot 1.3.0.RELEASEで動作します

@Autowired
private ConfigurableListableBeanFactory beanFactory;

// access a properties.yml file like properties
@Bean
public PropertySource properties() {
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    yaml.setResources(new ClassPathResource("properties.yml"));
    propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
    // properties need to be processed by beanfactory to be accessible after
    propertySourcesPlaceholderConfigurer.postProcessBeanFactory(beanFactory);
    return propertySourcesPlaceholderConfigurer.getAppliedPropertySources().get(PropertySourcesPlaceholderConfigurer.LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME);
}

0

Spring Bootで複数のプロファイル設定を含むカスタムymlファイルをロードする。

1)次のようにSpringBootApplicationを起動してプロパティBeanを追加します。

@SpringBootApplication
@ComponentScan({"com.example.as.*"})
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    @Profile("dev")
    public PropertySourcesPlaceholderConfigurer propertiesStage() {
        return properties("dev");
    }

    @Bean
    @Profile("stage")
    public PropertySourcesPlaceholderConfigurer propertiesDev() {
        return properties("stage");
    }

    @Bean
    @Profile("default")
    public PropertySourcesPlaceholderConfigurer propertiesDefault() {
        return properties("default");

    }
   /**
    * Update custom specific yml file with profile configuration.
    * @param profile
    * @return
    */
    public static PropertySourcesPlaceholderConfigurer properties(String profile) {
       PropertySourcesPlaceholderConfigurer propertyConfig = null;
       YamlPropertiesFactoryBean yaml  = null;

       propertyConfig  = new PropertySourcesPlaceholderConfigurer();
       yaml = new YamlPropertiesFactoryBean();
       yaml.setDocumentMatchers(new SpringProfileDocumentMatcher(profile));// load profile filter.
       yaml.setResources(new ClassPathResource("env_config/test-service-config.yml"));
       propertyConfig.setProperties(yaml.getObject());
       return propertyConfig;
    }
}

2)Java pojoオブジェクトを次のように構成します

@Component
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
@ConfigurationProperties(prefix = "test-service")
public class TestConfig {

    @JsonProperty("id") 
    private  String id;

    @JsonProperty("name")
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   

}

3)カスタムymlを作成します(次のようにリソースパスの下に配置します。YMLファイル名:test-service-config.yml)

たとえば、ymlファイルのConfigです。

test-service: 
    id: default_id
    name: Default application config
---
spring:
  profiles: dev

test-service: 
  id: dev_id
  name: dev application config

--- 
spring:
  profiles: stage

test-service: 
  id: stage_id
  name: stage application config

0

カスタムファイルプロパティの名前が原因で、@ ConfigurationPropertiesクラスを読み込めないという特定の状況にありました。最後に機能したのは(@Mateusz Balbusに感謝)だけです。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {MyTest.ContextConfiguration.class})
public class MyTest {

    @TestConfiguration
    public static class ContextConfiguration {

        @Autowired
        ApplicationContext applicationContext;

        @Bean
        public ConfigurationPropertiesBean myConfigurationPropertiesBean() throws IOException {
            Resource resource = applicationContext.getResource("classpath:my-properties-file.yml");

            YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
            List<PropertySource<?>> loadedSources = sourceLoader.load("yamlTestProperties", resource);
            PropertySource<?> yamlTestProperties = loadedSources.get(0);
            ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment)applicationContext.getEnvironment();
            configurableEnvironment.getPropertySources().addFirst(yamlTestProperties);

            Binder binder = Binder.get(applicationContext.getEnvironment());
            ConfigurationPropertiesBean configurationPropertiesBean = binder.bind("my-properties-file-prefix", Bindable.of(ConfigurationPropertiesBean.class)).get();
            return configurationPropertiesBean;
        }

    }

    @Autowired
    ConfigurationPropertiesBean configurationPropertiesBean;

    @Test
    public void test() {

        configurationPropertiesBean.getMyProperty();

    }

}

0
<dependency>
  <groupId>com.github.yingzhuo</groupId>
  <artifactId>spring-boot-stater-env</artifactId>
  <version>0.0.3</version>
</dependency>

私のライブラリを使用することを歓迎します。今YAMLtomlhoconがサポートされています。

出典:github.com


0

これは元の質問に対する回答ではありませんが、テストで異なる構成を必要とするための代替ソリューションです...

代わりに@PropertySourceを使用できます-Dspring.config.additional-location=classpath:application-tests.yml

接尾辞testsはプロファイルを意味しないことに注意してください...

その1つのYAMLファイルでは、複数のプロファイルを指定でき、相互に継承することができます。詳細はこちら- 複数のSpringプロファイルのプロパティ解決(yaml構成)

その後、あなたは(使用して、アクティブなプロファイルがあること、あなたのテストに指定することができます@ActiveProfiles("profile1,profile2"))されているprofile1,profile2場所をprofile2単純に上書きしますからプロパティを(いくつかを、人はすべてをオーバーライドする必要はありません)profile1


0

リストされたすべての質問を試しましたが、それらのすべてが私のタスクには機能しません:ユニットテストに特定のyamlファイルを使用します。私の場合、それはこのように機能します:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = {ConfigFileApplicationContextInitializer.class})
@TestPropertySource(properties = {"spring.config.location=file:../path/to/specific/config/application.yml"})
public class SomeTest {


    @Value("${my.property.value:#{null}}")
    private String value;

    @Test
    public void test() {
        System.out.println("value = " + value);
    }

}

-6

YamlPropertyLoaderFactoryやYamlFileApplicationContextInitializerのように追加する必要はありません。あなたのアイデアを変換する必要があります。一般的な春のプロジェクトのように。Java configを使用しないでください。ただ* .xml

次の手順を実行します:

のような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-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
       default-autowire="byName">

    <context:property-placeholder location="classpath*:*.yml"/>
</beans>

それから加えて

@ImportResource({"classpath:applicationContext.xml"})

あなたにApplicationMainClass

これは、application-test.ymlのスキャンに役立ちます

db:
  url: jdbc:oracle:thin:@pathToMyDb
  username: someUser
  password: fakePassword

質問はyamlに関連していました(これはIMHOが適切な構成方法です)
aldebaran-ms
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.