Spring @PropertySource с использованием YAML
Spring Загрузка позволяет нам заменить наши файлы application.properties эквивалентами YAML. Однако я, кажется, попал в ловушку с моими испытаниями. Если я аннотирую my 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 в своих тестах?
Ответы
Ответ 1
Spring-boot имеет помощника для этого, просто добавьте
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
в верхней части ваших тестовых классов или абстрактного тестового суперкласса.
Редактировать: я написал этот ответ пять лет назад. Он не работает с последними версиями Spring Boot. Это то, что я делаю сейчас (пожалуйста, переведите Kotlin на Java, если необходимо):
@TestPropertySource(locations=["classpath:application.yml"])
@ContextConfiguration(
initializers=[ConfigFileApplicationContextInitializer::class]
)
добавляется сверху, затем
@Configuration
open class TestConfig {
@Bean
open fun propertiesResolver(): PropertySourcesPlaceholderConfigurer {
return PropertySourcesPlaceholderConfigurer()
}
}
к контексту.
Ответ 2
Как уже упоминалось, @PropertySource
не загружает файл yaml. В качестве обходного решения загрузите файл самостоятельно и добавьте загруженные свойства в 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
}
}
Ответ 3
@PropertySource
поддерживает только файлы свойств (это ограничение от Spring, а не сама загрузка). Не стесняйтесь открывать билет функции в JIRA.
Ответ 4
@PropertySource
может быть настроен с помощью factory
аргумента. Так что вы можете сделать что-то вроде:
@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);
}
}
Вдохновленный fooobar.com/questions/2428336/...
Ответ 5
Из Spring Загрузите 1.4, вы можете использовать новую аннотацию @SpringBootTest
, чтобы добиться этого легче (и упростить установку интеграции в целом), загрузив ваши интеграционные тесты, используя Spring Поддержка загрузки.
Подробности в Spring Блог.
Насколько я могу судить, это означает, что вы получаете все преимущества Spring Boot внешний вид конфигурации, как и в вашем производственном коде, включая автоматический выбор конфигурации YAML из пути к классам.
По умолчанию эта аннотация будет
... сначала попытайтесь загрузить @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
Ответ 6
Другой вариант - установить spring.config.location
через @TestPropertySource
:
@TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }
Ответ 7
Подход к загрузке свойств yaml, IMHO может быть выполнен двумя способами:
а. Вы можете поместить конфигурацию в стандартное местоположение - application.yml
в корневой каталог пути - обычно src/main/resources
, и это свойство yaml должно автоматически загружаться при загрузке Spring с указанным вами именем сглаженного пути.
б. Второй подход является немного более обширным, в основном определяющим класс для хранения ваших свойств следующим образом:
@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties {
private String url;
private String username;
private String password;
...
}
По сути, это говорит о том, что загружает файл yaml и заполняет класс DbProperties на основе корневого элемента "db".
Теперь, чтобы использовать его в любом классе, вам нужно будет сделать это:
@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {
@Autowired private DbProperties dbProperties;
}
Любой из этих подходов должен работать для вас с помощью Spring -boot.
Ответ 8
Я нашел обходное решение, используя @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).
Ответ 9
в тестовом блоке @value имеет некоторые проблемы для свойства вызова из файла свойств, поэтому вы можете использовать среду для замены значения
@Autowired
private Environment environment;
public void init(){
String username=environment.getRequiredProperty("db.username");
}
чтобы вы могли вызвать свойство сейчас как в производственном, так и в тестовом блоке
Ответ 10
потому что вы не настроили snakeyml.
spring boot поставляется с функцией @EnableAutoConfiguration.
есть также snakeyml config, когда вы вызываете эту аннотацию.
это мой путь:
@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}
вот мой тест:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
classes = {
AppContextTest.class,
JaxbConfiguration.class,
}
)
public class JaxbTest {
//tests are ommited
}
Ответ 11
Мне нужно было прочитать некоторые свойства в моем коде, и это работает с 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);
}
Ответ 12
Загрузка пользовательского файла yml с несколькими конфигурациями профиля в Spring Загрузка.
1) Добавьте свойство bean с запуском SpringBootApplication следующим образом
@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
Например, Config в файле yml.
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
Ответ 13
Усиление ответа Матеуша Бальбуса.
Модифицированный класс YamlFileApplicationContextInitializer
котором местоположение YAML определяется для каждого тестового класса. К сожалению, это не работает на тест.
public abstract class YamlFileApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
/***
* Return location of a YAML file, e.g.: classpath:file.yml
*
* @return YAML file location
*/
protected abstract String getResourceLocation();
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
Resource resource = applicationContext.getResource(getResourceLocation());
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
PropertySource<?> yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null);
applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Использование:
Создайте подкласс YamlFileApplicationContextInitializer
с определенным getResourceLocation()
и добавьте этот подкласс в аннотацию @SpringApplicationConfiguration
.
Я думаю, что самому тестовому классу проще всего сделать этот конкретный подкласс, как в следующем примере.
@RunWith(SpringRunner.class)
@SpringApplicationConfiguration(classes = Application.class, initializers = SimpleTest.class)
public class SimpleTest extends YamlFileApplicationContextInitializer {
@Override
protected String getResourceLocation() {
return "classpath:test_specific.yml";
}
@Test
public test(){
// test your properties
}
}
Ответ 14
Вы можете настроить @PropertySource
для загрузки файлов YAML, @PropertySource
класс в атрибуте factory
. Я реализовал версию, которая также может учитывать активные профили вашего развертывания :).
https://medium.com/@james.tran/how-to-read-profile-based-yaml-configurations-with-propertysource-8131c16b3fc6
Ответ 15
Я находился в определенной ситуации, когда не мог загрузить класс @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();
}
}
Ответ 16
нет необходимости добавлять, например, YamlPropertyLoaderFactory или YamlFileApplicationContextInitializer.
Вы должны преобразовать свою идею. так же, как общий весенний проект. Вы знаете, не используя конфигурацию Java.
просто *.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
Слава богу, все работает хорошо!