I have this code that scans Spring context:
public void scan() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(SomeConfig.class);
context.refresh();
}
I need properties to be read from application.yml
file, so in SomeConfig
class, I have this:
@Configuration
@PropertySource(value = "classpath:application.yml", factory = YamlPropertyLoaderFactory.class)
public class SomeConfig {
//some beans
}
(I have copied YamlPropertyLoaderFactory class from here)
application.yml
is a typical Spring Boot file with some properties by profile, and a default profile:
spring:
profiles:
active: p1
---
spring:
profiles: p1
file: file1.txt
---
spring:
profiles: p2
file: file2.txt
In some bean, I'm reading file
property using @Value
.
When I run my application, I'm passing -Dspring.profiles.active=p1
variable, but I'm getting an error:
Could not resolve placeholder 'file' in value "${file}"
(It should work even if I don't pass any profile since application.yml has default profile set to p1)
If I remove all profiles config from application.yml
, it works fine:
file: file1.txt
So, it means that context scan is not reading the profile variable.
Also, if I set active profile "programatically", it doesn't resolve the properties either:
context.getEnvironment().setActiveProfiles("p1");
Since you'r using application. yml file, you don't need to manually load the file to the context as it's the default config file for spring application. You can simply use them in a @Component decorated class like below; @Value("${app.
To read from the application. yml or property file : The easiest way to read a value from the property file or yml is to use the spring @value annotation.
The YamlPropertyLoaderFactory
you refer to has the following code:
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);
}
}
The third parameter to the YamlPropertySourceLoader.load()
method is actually the profile name that you want the properties for. As this example passes in null it just returns the set of properties from the yml file not for a specific profile.
i.e.
spring:
profiles:
active: p1
---
I don't think it's easy to pick up the active profile name in the YamlPropertyLoaderFactory
, although you could try something like...
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null){
return super.createPropertySource(name, resource);
}
String activeProfile = System.getProperty("spring.profiles.active");
return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), activeProfile);
}
}
Or as you have the active profile name in the yml file, you could call YamlPropertySourceLoader().load
with null to get the spring.profiles.active property then call it again to load the actual part of the yml file you want.
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null){
return super.createPropertySource(name, resource);
}
PropertySource<?> source = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null);
String activeProfile = source.getProperty("spring.profiles.active");
return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), activeProfile);
}
}
YamlPropertySourceLoader
was changed back in feb 2018 (YamlPropertySourceLoader blame view in Git repo). It now returns a list of propertySource and does not have the third parameter on the load method.
Provided you have the spring.profiles.active property in the yml file you'd be able to do the following with the newer version of YamlPropertySourceLoader
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null){
return super.createPropertySource(name, resource);
}
List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
for (PropertySource<?> checkSource : sources) {
if (checkSource.containsProperty("spring.profiles.active")) {
String activeProfile = (String) checkSource.getProperty("spring.profiles.active");
for (PropertySource<?> source : sources) {
if (activeProfile.trim().equals(source.getProperty("spring.profiles"))) {
return source;
}
}
}
}
return sources.get(0);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With