starter - spring boot wikipedia
Spring @PropertySource usando YAML (12)
Spring Boot nos permite reemplazar nuestros archivos application.properties con equivalentes YAML. Sin embargo, parece que me tocó un inconveniente con mis pruebas. Si TestConfiguration
mi TestConfiguration
(una simple configuración de Java), está esperando un archivo de propiedades.
Por ejemplo, esto no funciona: @PropertySource(value = "classpath:application-test.yml")
Si tengo esto en mi archivo YAML:
db:
url: jdbc:oracle:thin:@pathToMyDb
username: someUser
password: fakePassword
Y estaría aprovechando esos valores con algo como esto:
@Value("${db.username}") String username
Sin embargo, termino con un error así:
Could not resolve placeholder ''db.username'' in string value "${db.username}"
¿Cómo puedo aprovechar la bondad YAML en mis pruebas también?
Cargar archivo yml personalizado con configuración de perfil múltiple en Spring Boot.
1) Agregue el bean de propiedad con el inicio de SpringBootApplication de la siguiente manera
@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) Configure el objeto pojo de Java de la siguiente manera
@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) Cree el yml personalizado (y colóquelo en la ruta del recurso de la siguiente manera, nombre de archivo YML: test-service-config.yml
Ej Config en el archivo 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
Como se mencionó @PropertySource
no carga el archivo yaml. Como solución, cargue el archivo por su cuenta y agregue propiedades cargadas a Environment
.
Implemento 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);
}
}
}
Agregue su inicializador a su prueba:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class)
public class SimpleTest {
@Test
public test(){
// test your properties
}
}
Desde Spring Boot 1.4, puede usar la nueva anotación @SpringBootTest
para lograr esto más fácilmente (y para simplificar la configuración de su prueba de integración en general) mediante el arranque de sus pruebas de integración utilizando la compatibilidad con Spring Boot.
Detalles sobre el blog de primavera .
Por lo que puedo decir, esto significa que obtienes todos los beneficios de la bondad de configuración externalizada de Spring Boot como en tu código de producción, incluida la configuración de YAML desde el classpath.
Por defecto, esta anotación
... primer intento de cargar
@Configuration
desde cualquier clase interna, y si eso falla, buscará su clase primaria@SpringBootApplication
.
pero puede especificar otras clases de configuración si es necesario.
Para este caso en particular, puede combinar @SpringBootTest
con @ActiveProfiles( "test" )
y Spring recuperará su configuración de YAML, siempre que siga los estándares de nomenclatura Boot (es decir, application-test.yml
).
@RunWith( SpringRunner.class )
@SpringBootTest
@ActiveProfiles( "test" )
public class SpringBootITest {
@Value("${db.username}")
private String username;
@Autowired
private MyBean myBean;
...
}
Nota: SpringRunner.class
es el nuevo nombre de SpringJUnit4ClassRunner.class
El enfoque para cargar las propiedades yaml, en mi humilde opinión puede hacerse de dos maneras:
a. Puede poner la configuración en una ubicación estándar - application.yml
en la raíz de classpath - típicamente src/main/resources
y esta propiedad yaml debe ser cargada automáticamente por Spring con el nombre de ruta plana que ha mencionado.
segundo. El segundo enfoque es un poco más extenso, básicamente define una clase para mantener tus propiedades de esta manera:
@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties {
private String url;
private String username;
private String password;
...
}
Básicamente, esto significa que cargue el archivo yaml y complete la clase DbProperties en función del elemento raíz de "db".
Ahora para usarlo en cualquier clase, tendrás que hacer esto:
@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {
@Autowired private DbProperties dbProperties;
}
Cualquiera de estos enfoques debería funcionar limpiamente con Spring-boot.
Encontré una solución utilizando @ActiveProfiles("test")
y agregando un archivo application-test.yml a src / test / resources.
Terminó luciendo así:
@SpringApplicationConfiguration(classes = Application.class, initializers = ConfigFileApplicationContextInitializer.class)
@ActiveProfiles("test")
public abstract class AbstractIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests {
}
El archivo application-test.yml solo contiene las propiedades que deseo sobrescribir de application.yml (que se puede encontrar en src / main / resources).
Mejorando la respuesta Mateusz Balbus .
Se modificó la clase YamlFileApplicationContextInitializer
donde se define la ubicación de YAML por clase de prueba. No funciona por prueba, desafortunadamente.
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);
}
}
}
Uso:
Cree la subclase de YamlFileApplicationContextInitializer
con el método getResourceLocation()
definido y agregue esta subclase a la anotación @SpringApplicationConfiguration
.
Creo que es más fácil hacer que la clase de prueba en sí misma esa subclase específica como en el siguiente ejemplo.
@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
}
}
Necesitaba leer algunas propiedades en mi código y esto funciona con 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);
}
Otra opción es establecer spring.config.location
través de @TestPropertySource
:
@TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" }
Spring-boot tiene un ayudante para esto, solo agrega
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
en la parte superior de las clases de prueba o una superclase de prueba abstracta.
es porque no has configurado snakeyml. el arranque de primavera viene con la característica @EnableAutoConfiguration. también hay una configuración de snakeyml cuando llamas a esta anotación ...
Esta es mi manera:
@Configuration
@EnableAutoConfiguration
public class AppContextTest {
}
aquí está mi prueba:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(
classes = {
AppContextTest.class,
JaxbConfiguration.class,
}
)
public class JaxbTest {
//tests are ommited
}
@PropertySource
se puede configurar por argumento de factory
. Entonces puedes hacer algo como:
@PropertySource(value = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class)
Donde YamlPropertyLoaderFactory
es su cargador de propiedades personalizado:
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);
}
}
Inspirado por https://.com/a/45882447/4527110
@PropertySource
solo admite archivos de propiedades (es una limitación de Spring, no de Boot). No dude en abrir un ticket de solicitud de función en JIRA .