YAML kullanan Spring @PropertySource


109

Spring Boot, application.properties dosyalarımızı YAML eşdeğerleriyle değiştirmemize olanak tanır. Ancak testlerimde bir engele çarpmış gibi görünüyorum. Benim TestConfiguration(basit bir Java yapılandırması) açıklama eklersem , bir özellikler dosyası bekliyordur.

Örneğin bu işe yaramıyor: @PropertySource(value = "classpath:application-test.yml")

YAML dosyamda bu varsa:

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

Ve bu değerleri şunun gibi bir şeyle kullanıyorum:

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

Ancak, sonuçta şu şekilde hata yapıyorum:

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

Testlerimde de YAML iyiliğinden nasıl yararlanabilirim?


"Çalışmıyor" u tanımlayın. İstisna / hata / uyarı nedir?
Emerson Farrugia

Spring Boot, YAML dosyasını nokta notasyonlu bir özellik dosyası olarak görünecek şekilde düzleştirir. Bu düzleşme olmuyor.
checketts

Ve sadece onaylamak için, bu test dışı kodda çalışıyor?
Emerson Farrugia

1
Evet. İşte projects.spring.io/spring-boot/docs/spring-boot-actuator/… açıklayan bir belge ve sayfanın aşağısında 'YAML nesnesinin nokta ayırıcıları kullanılarak düzleştirildiğini unutmayın.'
2014

9
SpingBoot, PropertySource ile YAML'yi yükleyemediğini söyledi: 24.6.4 YAML eksiklikleri YAML dosyaları @PropertySource ek açıklaması yoluyla yüklenemez. Dolayısıyla, değerleri bu şekilde yüklemeniz gerektiğinde, bir özellikler dosyası kullanmanız gerekir.
Lex Pro

Yanıtlar:


56

Spring-boot bunun için bir yardımcıya sahip, sadece ekle

@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)

Test sınıflarınızın en üstünde veya soyut bir test süper sınıfı.

Düzenleme: Bu cevabı beş yıl önce yazdım. Spring Boot'un son sürümleriyle çalışmıyor. Şimdi yaptığım şey bu (gerekirse Kotlin'i lütfen Java'ya çevirin):

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

en üste eklenir, sonra

    @Configuration
    open class TestConfig {

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

bağlama göre.


3
Unutma PropertySourcesPlaceholderConfigurer
Kalpesh Soni

@KalpeshSoni, Yapılandırıcı demeden gerçekten işe yaramaz.
Ola Sundell

Bunun yerine başlatıcıyı @SpringJunitConfig'e eklemek zorunda kaldım@SpringJUnitConfig(value = {...}, initializers = {ConfigFileApplicationContextInitializer.class})
Tomas F

1
@ Jan Galinski cevabımı deneyebilirsiniz, kullanımı kolay ve ürün ortamımda iyi çalışıyor. stackoverflow.com/questions/21271468/…
Forest10

59

Bahsedildiği @PropertySourcegibi yaml dosyasını yüklemiyor. Geçici bir çözüm olarak dosyayı kendi başınıza yükleyin ve yüklenen özellikleriEnvironment .

Uygulama 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);
    }
  }
}

Başlatıcıyı testinize ekleyin:

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

Aslında bu en iyi cevap olmalı, işe yaradığı için teşekkürler!
Adelin

Mateusz, YamlFileApplicationContextInitializerYAML konumunun test senaryosu başına tanımlandığı sınıfta yanıt gönderdim . İlginç olduğunu düşünüyorsanız, cevabınızla birleştirmekten çekinmeyin, ben de benimkini sileceğim. Cevabımın altındaki bir yorumda bana haber vermeniz yeterli.
Michal Foksa

Evet, bu en iyi cevap
Richard HM

34

@PropertySourcefactorybağımsız değişken ile yapılandırılabilir . Böylece şöyle bir şey yapabilirsiniz:

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

YamlPropertyLoaderFactoryÖzel mülk yükleyiciniz nerede :

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 esinlenilmiştir


2
Bu temel yaml ayrıştırması IllegalStateException, dosya doğru yerine mevcut olmadığında bir atar FileNotFoundException- bu nedenle, bunun işe yaraması için @PropertySource(..., ignoreResourceNotFound = true), şu vakayı yakalamanız ve halletmeniz gerekir: try { return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null); } catch (IllegalStateException e) { throw (IOException) e.getCause(); }
Christian Opitz

2
Belirli bir profil için özellikler almanız gerekiyorsa, YamlPropertySourceLoader.load () içindeki üçüncü parametre profil adıdır. YamlPropertySourceLoader.load (), tek bir özellik kaynağı yerine bir liste döndürecek şekilde değiştirildi. İşte daha fazla bilgi stackoverflow.com/a/53697551/10668441
pcoates

1
Bu şimdiye kadarki en temiz yaklaşım.
Michal Foksa

7
benim için, aşağıdaki gibi küçük bir değişiklik gerektirdi:CompositePropertySource propertySource = new CompositePropertySource(name); new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource()).stream().forEach(propertySource::addPropertySource); return propertySource;
xorcus

28

@PropertySourceyalnızca özellikler dosyalarını destekler (bu, Boot'un kendisinden değil, Spring'den kaynaklanan bir sınırlamadır). Bir özellik isteği bileti açmak için çekinmeyin JIRA içinde .


Yaml dinleyicisini yeniden kullanmanın veya yaml'yi test yapılandırmasına geçirilebilecek bir Ortama manuel olarak yüklemenin bir yolu olduğunu ummuştum.
checketts

10
Sanırım bir yazabilir ApplicationContextInitializerve bunu test yapılandırmasına ekleyebilirsiniz (sadece a YamlPropertySourceLoaderkullanın Environment). Şahsen, @PropertySourcebu davranışı yerel olarak desteklemesini tercih ederim .
Dave Syer

hala durum bu mu? '@PropertySource' YAML'yi desteklemiyor mu?
domi

1
stackoverflow.com/questions/21271468/… bunu kullanın @PropertySource yalnızca özellik dosyalarını destekler
Forest10

Bu 6 yıllık yazıyla sorunumu çözdüğümü şok ettim.
Jin Kwon

21

Başka bir seçenek ayarlamaktır spring.config.locationyoluyla @TestPropertySource:

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

3
Girdiyi aşağıdaki satıra göre parametrelendirdim: @TestPropertySource(properties = {"spring.config.location=classpath:application-${test.env}.yml" }) IMO sizinki hepsinden en iyi cevaptır.
leventunver

1
Harika bir fikir ve testler için çok minimalist, çok teşekkürler! Eklemek @TestPropertySource(properties = {"spring.config.location=classpath:application-config.yml,classpath:test-config.yml,..." })
gerekirse

1
Bu şimdiye kadarki en iyi cevap! Eğer olması gerekir unutmayın @SpringBootTestek açıklama
Mistriel

19

Spring Boot 1.4'ten, @SpringBootTestSpring Boot desteğini kullanarak entegrasyon testlerinizi önyükleyerek bunu daha kolay başarmak (ve genel olarak entegrasyon testi kurulumunuzu basitleştirmek) için yeni açıklamayı kullanabilirsiniz .

İlgili ayrıntılar Bahar Blog .

Anlayabildiğim kadarıyla, bu , sınıf yolundan otomatik olarak YAML yapılandırmasını almak da dahil olmak üzere, üretim kodunuzda olduğu gibi Spring Boot'un haricileştirilmiş yapılandırma iyiliğinin tüm avantajlarından yararlanabileceğiniz anlamına gelir .

Varsayılan olarak, bu ek açıklama

... önce @Configurationherhangi bir iç sınıftan yüklemeyi deneyin ve bu başarısız olursa, birincil @SpringBootApplicationsınıfınızı arayacaktır .

ancak gerekirse diğer yapılandırma sınıflarını da belirtebilirsiniz.

Bu özel durum için, @SpringBootTestile birleştirebilirsiniz @ActiveProfiles( "test" )ve Spring, normal Boot adlandırma standartlarını (yani application-test.yml) izlemesi koşuluyla, YAML yapılandırmanızı alır .

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

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

    @Autowired
    private MyBean myBean;

    ...

}

Not: SpringRunner.classyeni adıSpringJUnit4ClassRunner.class


1
:) @ActiveProfiles kullanmak işe yarayan tek seçenektir. Teşekkürler!
zcourts

10

Yaml özelliklerini yükleme yaklaşımı olan IMHO iki şekilde yapılabilir:

a. Yapılandırmayı standart bir konuma ( application.ymlsınıf yolu köküne) koyabilirsiniz.src/main/resources ve bu yaml özelliği, bahsettiğiniz düzleştirilmiş yol adıyla Spring önyüklemesi tarafından otomatik olarak yüklenmelidir.

b. İkinci yaklaşım biraz daha kapsamlıdır, temelde mülklerinizi bu şekilde tutacak bir sınıf tanımlayın:

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

Yani esasen bu, yaml dosyasını yükleyip DbProperties sınıfını "db" nin kök öğesine göre doldurduğunu söylüyor.

Şimdi herhangi bir sınıfta kullanmak için şunu yapmanız gerekecek:

@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {

    @Autowired private DbProperties dbProperties;

}

Bu yaklaşımlardan herhangi biri, Spring-boot kullanarak sizin için temiz bir şekilde çalışmalıdır.


Sınıf yolunuzda snakeyml olduğundan emin olun ve yukarıdakiler işe yarayacaktır.
hoserdude

3
(Bu soru sorulmuştur anda olmasa da), Bu gün snakeyamlbir geçişli bağımlılık olarak yer çekilir spring-boot-starter, böylece eklemek gerek olmamalıdır sizin pom.xmlveya build.gradlefarklı bir sürümünü kullanmak için bir köklü dürtü var sürece. :)
Steve

2
Şimdi locationsdeğil pathve ConfigFileApplicationContextInitializeraynı zamanda gerekli.
OrangeDog

3

@ActiveProfiles("test")Src / test / resources konumuna bir application-test.yml dosyası kullanarak ve ekleyerek bir geçici çözüm buldum .

Sonunda şöyle göründü:

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

}

Application-test.yml dosyası yalnızca application.yml'den geçersiz kılmak istediğim özellikleri içeriyor (src / main / kaynaklarda bulunabilir).


Ben de kullanmaya çalıştığım şey buydu. Bazı nedenlerden dolayı kullandığım zaman çalışmıyor (Spring Boot 1.3.3) @Value("${my.property}")ama kullanırsam iyi çalışıyor environment.getProperty("my.property").
martin-g

1

çünkü snakeyml'yi yapılandırmamışsınızdır. Spring boot @EnableAutoConfiguration özelliği ile birlikte gelir. bu ek açıklamayı çağırdığınızda snakeyml yapılandırması da var ..

Bu benim yolum:

@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}

işte benim testim:

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

public class JaxbTest {
//tests are ommited
}

0

Kodumdaki bazı özellikleri okumam gerekiyordu ve bu ilkbahar-boot 1.3.0 ile çalışıyor.

@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'da çoklu profil yapılandırmasına sahip özel yml dosyası yükleniyor.

1) SpringBootApplication başlangıcında özellik çekirdeğini aşağıdaki gibi ekleyin

@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 nesnesini aşağıdaki gibi yapılandırın

@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) Özel yml'yi oluşturun (ve aşağıdaki gibi kaynak yolunun altına yerleştirin, YML Dosya adı: test-service-config.yml

Örneğin yml dosyasında Yapılandırma.

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

Özel dosya özelliği adlandırma nedeniyle @ConfigurationProperties sınıfını yükleyemediğim belirli bir durumdaydım. Sonunda işe yarayan tek şey (teşekkürler @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>

Kitaplığımı kullanmaya hoş geldiniz. Artık yaml , toml , hocon desteklenmektedir.

Kaynak: github.com


0

Bu, orijinal soruya bir cevap değil, bir testte farklı bir konfigürasyona sahip olma ihtiyacı için alternatif bir çözüm ...

@PropertySourceSenin yerine kullanabilirsin -Dspring.config.additional-location=classpath:application-tests.yml.

Bu son ekin testsprofil anlamına gelmediğini unutmayın ...

Bu bir YAML dosyasında, bir tür birbirinden miras alabilen birden çok profil belirtilebilir, buradan daha fazlasını okuyun - Birden çok Yay profili için özellik çözümleme (yaml yapılandırması)

Ardından, (kullanarak aktif profiller durumdadır ve test belirtebilirsiniz @ActiveProfiles("profile1,profile2")) vardır profile1,profile2nerede profile2basitçe geçersiz kılar gelen özelliklerini (bazı tek tüm geçersiz kılmak gerekmez) profile1.


0

Listelenen tüm soruları denedim, ancak hepsi görevim için çalışmıyor: bazı birim testleri için özel yaml dosyası kullanmak. Benim durumumda şu şekilde çalışıyor:

@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 veya YamlFileApplicationContextInitializer gibi eklemeye gerek yoktur. Fikrinizi dönüştürmelisiniz. tıpkı ortak yay projesi gibi. Bilirsiniz, Java yapılandırması kullanmıyorum. Yalnızca * .xml

Bu adımları takip et:

Sadece applicationContext.xml dosyasını şöyle ekleyin

<?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>

sonra Ekle

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

senin için ApplicationMainClass .

Bu, application-test.yml dosyanızın taranmasına yardımcı olabilir

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

Soru yaml ile ilgiliydi (IMHO iyi bir yapılandırma yöntemidir)
aldebaran-ms
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.