Spring Boot: настройка пользовательских свойств и тесты

Я использую Spring Boot 2.0 с файлом свойств по умолчанию application.yml. Я хотел бы разделить его на отдельные файлы свойств, потому что он становится огромным.
Также я хотел бы написать тесты для проверки правильности свойств: значений, которые будут представлены в контексте производственного приложения (не тестового).

Вот мой файл свойств: src/main/resources/config/custom.yml

my-property:
  value: 'test'

Класс недвижимости:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Data
@Configuration
@ConfigurationProperties(prefix = "my-property")
@PropertySource("classpath:config/custom.yml")
public class MyProperty {

  private String value;
}

Контрольная работа:

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@EnableConfigurationProperties
public class MyPropertyTest {

  @Autowired
  private MyProperty property;

  @Test
  public void test() {
    assertEquals("test", property.getValue());
  }

}

Но тест не проходит с ошибкой:

java.lang.AssertionError: 
Expected :test
Actual   :null

Также я вижу, что значение свойства равно null при запуске приложения, печатая его в ApplicationRunner.
Когда я использовал application.yml для всех свойств, это было хорошо с той же конфигурацией.

Как правильно настроить свойства и тесты, чтобы заставить их работать?
Ссылка на Github репозиторий


person Bullet-tooth    schedule 04.06.2018    source источник
comment
Вы пытались использовать аннотацию @TestPropertySource для указания местоположения ваших файлов конфигурации?   -  person Prashant    schedule 04.06.2018
comment
Кроме того, такие случаи легче отлаживать, если вы можете создать очень простое минимальное приложение и предоставить ссылку на него с github.   -  person Prashant    schedule 04.06.2018
comment
Возможный дубликат Spring @PropertySource с использованием YAML   -  person Shubhendu Pramanik    schedule 04.06.2018


Ответы (4)


Точно я нашел правильный способ иметь пользовательские свойства yaml в своем приложении.

Проблема в том, что Spring не поддерживает файлы yaml как @PropertySource (ссылка на проблему). И вот обходной путь, как справиться с этим, описанный в документация Spring.
Итак, чтобы иметь возможность загружать свойства из файлов yaml, вам нужно:
* реализовать EnvironmentPostProcessor
* зарегистрировать его в spring.factories

Полный пример можно найти в этом репозитории github.

Кроме того, большое спасибо за вашу поддержку, ребята!

person Bullet-tooth    schedule 05.06.2018

@TestPropertySource может решить вашу проблему.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyProperty.class)
@TestPropertySource(locations="classpath:test.properties")
public class MyPropertyTest {

@Autowired
private MyProperty property;

@Test
public void test() {
   assertEquals("test", property.getValue());
}
}

Надеюсь, поможет.

person Antariksh    schedule 04.06.2018
comment
Как упоминалось OP в принятом ответе, @TestPropertySource в настоящее время не работает с файлами yml. - person vmaldosan; 12.02.2019

Я немного опаздываю на вечеринку, но это тоже может помочь. Решение, представленное в качестве ответа, является лучшим подходом на данный момент, но вот альтернатива, которую я использовал

Используйте профили и измените bean-компонент PropertySoucesPlaceHolderConfiguration, чтобы он загружал необходимые файлы свойств на основе профилей. Он загружает application.properties по умолчанию, но другие файлы свойств -oauth_DEV и oauth_QA загружаются на основе установленных профилей.

@Bean
    public PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurerconfigurer() {

        System.out.println("Inside Placeholder bean");
        PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer();
        ClassPathResource cls1=  new ClassPathResource("application.properties");
         ClassPathResource cls2 = null;

        Map<String, Object> propMap = ((ConfigurableEnvironment) ctx.getEnvironment()).getSystemProperties();
        for(Map.Entry<String, Object> entrySet: propMap.entrySet()) {
            System.out.println("Map.Key:"+entrySet.getKey()+"  Map.valiue:"+entrySet.getValue());
        }

        List<String> profiles=  Arrays.asList(ctx.getEnvironment().getActiveProfiles());
        if(profiles == null || profiles.isEmpty()) {
            if(!propMap.containsKey("spring.profiles.active")) {
                cls2 = new ClassPathResource("oauth-default.properties");
            } else {
                cls2 = new ClassPathResource("oauth-"+propMap.get("spring.profiles.active")+".properties");
            }
        }else {
            for(String profile:profiles) {
                if(profile.equalsIgnoreCase("DEV")) {
                    cls2 =  new ClassPathResource("oauth-DEV.properties");
                }else if(profile.equalsIgnoreCase("QA")) {
                    cls2 =  new ClassPathResource("oauth-QA.properties");
                }else if (profile.equalsIgnoreCase("UAT")) {
                    cls2 =  new ClassPathResource("oauth-UAT.properties");
                }else if(profile.equalsIgnoreCase("PROD")){
                    cls2 =  new ClassPathResource("oauth-PROD.properties");
                }else {
                    cls2 = new ClassPathResource("oauth-default.properties");
                }
            }
        }

        cfg.setLocations(cls1,cls2);
        //cfg.setPlaceholderPrefix("#{");
        return cfg;
    }

Затем создайте еще один bean-компонент, который считывает свойства на основе префикса — «security.oauth2.client».

@Configuration
@ConfigurationProperties(prefix="security.oauth2.client")
public class OauthSecurityConfigurationDto {

    private String clientId;
    private String clientSecret;
    private String scope;
    private String accessTokenUri;
    private String userAuthorizationUri;
    private String grantType;
    private String resourceIds;
    private String registeredRedirectUri;
    private String preEstablishedRedirectUri;
    private String useCurrentUri;
    private String userInfoUri;
    public String getClientId() {
        return clientId;
    }
    public void setClientId(String clientId) {
        this.clientId = clientId;
    }
    public String getClientSecret() {
        return clientSecret;
    }
    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    public String getAccessTokenUri() {
        return accessTokenUri;
    }
    public void setAccessTokenUri(String accessTokenUri) {
        this.accessTokenUri = accessTokenUri;
    }
    public String getUserAuthorizationUri() {
        return userAuthorizationUri;
    }
    public void setUserAuthorizationUri(String userAuthorizationUri) {
        this.userAuthorizationUri = userAuthorizationUri;
    }
    public String getGrantType() {
        return grantType;
    }
    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }
    public String getResourceIds() {
        return resourceIds;
    }
    public void setResourceIds(String resourceIds) {
        this.resourceIds = resourceIds;
    }
    public String getRegisteredRedirectUri() {
        return registeredRedirectUri;
    }
    public void setRegisteredRedirectUri(String registeredRedirectUri) {
        this.registeredRedirectUri = registeredRedirectUri;
    }
    public String getPreEstablishedRedirectUri() {
        return preEstablishedRedirectUri;
    }
    public void setPreEstablishedRedirectUri(String preEstablishedRedirectUri) {
        this.preEstablishedRedirectUri = preEstablishedRedirectUri;
    }
    public String getUseCurrentUri() {
        return useCurrentUri;
    }
    public void setUseCurrentUri(String useCurrentUri) {
        this.useCurrentUri = useCurrentUri;
    }
    public String getUserInfoUri() {
        return userInfoUri;
    }
    public void setUserInfoUri(String userInfoUri) {
        this.userInfoUri = userInfoUri;
    }


}

Помните, что сеттеры важны, потому что ConfigurationProperties загружают значения в свойства класса только тогда, когда определены геттеры и сеттеры.

Теперь мы можем автоматически подключить зависимость везде, где это необходимо, и использовать это свойство.

person vijayakumarpsg587    schedule 28.10.2018

Если это ваш точный код, это означает, что вы читаете свое свойство из неправильного файла свойств.

замените свой ресурс собственности на эту строку.

@PropertySource("classpath:config/services.yml")
person Ravat Tailor    schedule 04.06.2018
comment
Спасибо за Ваш ответ. Извините, я пропустил это и исправил в своем вопросе. Но это не помогает :(. - person Bullet-tooth; 04.06.2018
comment