I am looking to replace the Environment bean used by Spring with my own implementation. Is this bad-practice, and if not, how can I do this cleanly? Currently I have created a bean that implements the Environment interface and uses the existing Environment bean, but this means all the configuration code needing the Environment bean must now use my custom Environment bean. I would think it would be cleaner to replace Springs Environment bean with my own, then no configuration needing it would need to change. Currently the only way I can think to do this would be to either create my own ApplicationContext thus setting the environment to my own, or to have something be ApplicationContextAware and set the environment there. Both of these seem to be a bit hokey to me.
Constraints:
I am using the latest version of Spring3.
I am using Java based configuration; not XML
Thank you.
Edit: Background
I suppose I should explain why I want to do this in case my thinking is flawed. I was avoid this in order to avoid the nonconstructive "why would you want to do that?" responses.
The Spring Environment bean, when looking for property values, uses a set of property sources. A typical stack looks like this (but is not limited to):
JNDI
System Properties (set via -Dmyprop=foo)
Environment Variables
...
For security reason, it is necessary to encrypt some of these properties (e.g. database passwords). The go to solution is to use Jasypt for property encryption. However, the Spring/Jasypt only provide a means of inserting a new property source into the environment. So:
Property file with potentially encrypted values
JNDI
System Properties (set via -Dmyprop=foo)
Environment Variables
...
However, this is not ideal as this means that properties can only be stored in a single file to be maintained by the operations group or that properties would be spread out amongst property files, environment variables, etc. In addition, I feel that properties have the potential of being encrypted regardless of their property source.
So this lead me to thinking that I either need to decrypt the properties in my code wherever I attempt to access them from the environment, or I need to create my own Environment bean that can do this for me.
I'm welcome to hear constructive comments and alternatives.
EDIT: Adding solution based on answer from M. Deinum
public class EnvironmentBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static final String CONFIGURATION_PROPERTY_PBE_ALGORITHM = "PBE_ALGORITHM";
private static final String CONFIGURATION_PROPERTY_PBE_PASSWORD = "PBE_PASSWORD";
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
StandardEnvironment environment = (StandardEnvironment) beanFactory.getBean("environment");
if (environment != null) {
StringEncryptor encryptor = this.getEncryptor(environment);
MutablePropertySources mutablePropertySources = environment.getPropertySources();
for (PropertySource<?> propertySource : mutablePropertySources) {
mutablePropertySources.replace(
propertySource.getName(),
new EncryptablePropertySourcePropertySource(propertySource.getName(), propertySource, encryptor));
}
}
}
private StringEncryptor getEncryptor(Environment environment) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
String algorithm = environment.getProperty(CONFIGURATION_PROPERTY_PBE_ALGORITHM);
if (algorithm != null) {
encryptor.setAlgorithm(algorithm);
}
String password = environment.getProperty(CONFIGURATION_PROPERTY_PBE_PASSWORD);
if (password != null) {
encryptor.setPassword(password);
}
return encryptor;
}
private class EncryptablePropertySourcePropertySource extends PropertySource<PropertySource<?>> {
private StringEncryptor stringEncryptor;
private TextEncryptor textEncryptor;
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final StringEncryptor encryptor) {
super(name, propertySource);
this.stringEncryptor = encryptor;
}
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final TextEncryptor encryptor) {
super(name, propertySource);
this.textEncryptor = encryptor;
}
#Override
public Object getProperty(String name) {
Object value = this.source.getProperty(name);
if (value != null && value instanceof String) {
value = this.decode((String) value);
}
return value;
}
private String decode(String encodedValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(encodedValue)) {
return encodedValue;
}
if (this.stringEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.stringEncryptor);
}
if (this.textEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.textEncryptor);
}
throw new EncryptionOperationNotPossibleException(
"Neither a string encryptor nor a text encryptor exist "
+ "for this instance of EncryptableProperties. This is usually "
+ "caused by the instance having been serialized and then "
+ "de-serialized in a different classloader or virtual machine, "
+ "which is an unsupported behaviour (as encryptors cannot be "
+ "serialized themselves)");
}
}
}
However, the Spring/Jasypt only provide a means of inserting a new property source into the environment.
Actually that is where you are wrong, you can replace PropertySources as well. See the javadoc of MutablePropertySources. This is also used internally by Spring to first add some dummy PropertySources and replace them later.
What you could do is create a PropertySource which delegates to another PropertySource and decrypts the value on the fly. That way you could replace all PropertySources with a one which wraps around the original.
MutablePropertySources mps = env.getgetPropertySources();
for (PropertySource ps : env.getgetPropertySources()) {
EncryptablePropertySource eps = new EncryptablePropertySource(ps.getName(), ps, encryptor);
mps.replace(ps.getName(), eps);
}
You could use the EncryptablePropertiesPropertySource as a sample, what you basically need to do is replace the Properties with PropertySource.
It would be easier if SPR-8928 would be fixed as that would allow simply for the EncryptedPropertySourcesPlaceholderConfigurer to be registered and all properties would converted and you wouldn't need these hacks.
Related
My use case is a bit oddball but basically, I'd like to read a portion of a yaml file and map it to the appropriate java object in a spring application. This is a pretty common and trivial operation in spring (just use #ConfigurationProperties ).
However, in my case, I'd like to accomplish this reading earlier in the lifecycle i.e. by the time the BeanFactoryPostProcessor hooks in - in order to use the instructions specified in yml to dynamically create a number of beans.
I can get this working with application.properties but not with application.yml
I was hoping to use yml in order leverage mapping part of the yml to POJO and also utilize hierarchical mapping files and data structures (lists, maps etc).
Here's an example of how to read application.properties. https://blog.pchudzik.com/201705/dynamic-beans/
I set up a simple skeleton project at https://github.com/balamuru/yaml-loader to try out different techniques.
Any ideas ?
#Component
#EnableConfigurationProperties(SampleDataConfig.class)
class ConfigurableBeanFactory implements BeanFactoryPostProcessor, InitializingBean {
private List<String> beanInstances = new ArrayList<>();
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
Map<String, SampleDataConfig> beans = beanFactory.getBeansOfType(SampleDataConfig.class);
System.err.println("");
beanInstances.forEach(instance -> {
registry.registerBeanDefinition(instance, BeanDefinitionBuilder
.rootBeanDefinition(SampleDataConfig.class)
.addConstructorArgValue(instance)
.getBeanDefinition());
});
}
#Override
public void afterPropertiesSet() throws Exception {
// this.beanInstances = asList(PropertiesLoaderUtils
// .loadProperties(new ClassPathResource("/application.properties"))
// .getProperty("dynamic-beans.instances", "")
// .split(","));
/**
* Rather than reading from application.properties,
* I would like to be able to load up the relevant prefix qualified segments (com.foo.bar.stuff) mapping to my POJO (SampleDataConfig,class)
* loaded from application.yml
*/
}
}
Internally, spring uses the following mechanism, but I was hoping there is an easier way to leverage this without re-inventing the spring :)
public class ConfigurationPropertiesBindingPostProcessor ...{
.
.
private void postProcessBeforeInitialization(Object bean, String beanName,
ConfigurationProperties annotation) {
Object target = bean;
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
target);
factory.setPropertySources(this.propertySources);
factory.setValidator(determineValidator(bean));
// If no explicit conversion service is provided we add one so that (at least)
// comma-separated arrays of convertibles can be bound automatically
factory.setConversionService(this.conversionService == null
? getDefaultConversionService() : this.conversionService);
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
if (StringUtils.hasLength(annotation.prefix())) {
factory.setTargetName(annotation.prefix()); //====> use annotation prefix
}
}
try {
factory.bindPropertiesToTarget(); //===> bind properties
}
Thanks
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
configProperty = yaml.getObject();
Set<Object> keys = configProperty.keySet();
Below is my YAML configuration, which looks like:
template:
config:
broker-urls:
- tcp://127.0.0.1:61616
- tcp://127.0.0.1:61617
- tcp://127.0.0.1:61618
qeues:
- Test
- Demo
- Qeue3
After applying above code you will get converted properties like below:
template.config.broker-urls[0]=tcp://127.0.0.1:61616
template.config.broker-urls[1]=tcp://127.0.0.1:61617
template.config.broker-urls[1]=tcp://127.0.0.1:61618
template.config.qeues[0]=Test
template.config.qeues[1]=Demo
template.config.qeues[1]=Qeue3
I would like to create a proper properties management strategy in a java webapp that relays on google guice as a DI framework.
I would like to have a mechanism answering the following 3 requirements:
I would like to be able to inject properties using guice (#Named)
I would like to be able to access properties in a static way
The mechanism should support prioritization of properties, meaning that a property can be wrapped in the deployed war with a certain value but it can also be redundant in the target system level or local file system (of the target machine I deploy on), in such a case the value in the war will be overridden by the value that exists in the target machine.
I believe this is a standard requirement. Now, using guice standard binder I can easily get the first requirement but not the other two. To get the other two I created my own class that does the following:
Wraps and exposes the binding methods of guice (those that binds properties) For example:
public static void bindString(AnnotatedBindingBuilder<String> binder, String property, String defaultValue) {
binder.annotatedWith(Names.named(property)).toInstance(getProperty(property, defaultValue));
}
Where the getProperty method knows how to handle my properties (get the value from the war or system level) and exposes the properties statically as well.
So basically as long as I'm using this utility that I created for properties bindings I'm good, it covers all my requirements but once I use the standard guice bindings I'm losing the second and third requirement.
Is there a way to override guice bindings and get all those 3 requirements?
Once I had the same challange in a spring based app and was pretty easy. I implemented ApplicationContextInitializer with the following method:
#Override
public void initialize(ConfigurableWebApplicationContext ctx) {
PropertySource<Map<String, Object>> localProps = null;
try {
localProps = new ResourcePropertySource(new ClassPathResource(LOCAL_PROPERTIES_FILE_NAME));
} catch (IOException e) {
LOG.fatal("Could not load local properties from classpath " + LOCAL_PROPERTIES_FILE_NAME);
return;
}
LOG.info("Loaded configuration from classpath local file " + LOCAL_PROPERTIES_FILE_NAME);
ctx.getEnvironment().getPropertySources().addFirst(localProps);
}
so this gave me a way to add local properties with highest priority to my Environment. In case of overlap with war properties the local ones had higher priority. In addition I exposed my Environment statically so I has static access to my properties (for services that are not managed by the container, legacy mostly).
How can I achieve this with guice?
Unfortunately, I don't think that you are going to find anything that gives you a truly clean and satisfying implementation. Especially, I don't think that you will find anything that gives you exactly what you want without implementing at least portions of it yourself.
If I had those needs, I would make sure that my injector is created in a central InjectorFactory. If you require a large number of parameters from outside to create your injector, I would simply create it once at the very beginning of my application and then cache the injector into a static final field. This would make it available to a static method. I would bind my "fall-back" property loading to an explicit provider. That way, instead of using the standard Names.bindProperties(...) method, I would bind it directly to a Provider. This provider then implements the logic that is necessary to perform the fallback or to merge multiple property files. Having the injector cached to a static field means that I can call a static method to access properties from a global-context outside of my injected classes.
Using your own provider seems initially unpleasant, but can provide some additional benefits. For starters, you can implement your fallback strategy exactly how you want. Additionally, you can add additional behaviors such as auto-reloading your property files, etc (not shown in my code sample).
public class InjectorFactory {
private static Injector injector = null;
public static synchronized Injector getOrCreateInjector() {
if(injector == null) {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
Properties properties1 = createProperties("file1.properties");
Properties properties2 = createProperties("file2.properties");
Set<Object> propertyNames = new HashSet<Object>();
propertyNames.addAll(properties1.keySet());
propertyNames.addAll(properties2.keySet());
for (Object object : propertyNames) {
String propertyName = (String) object;
bind(String.class).annotatedWith(Names.named(propertyName)).toProvider(new StringProvider(properties1, properties2, propertyName));
}
}
private Properties createProperties(String propertyFileName) {
try {
InputStream stream = InjectorFactory.class.getResourceAsStream(propertyFileName);
try {
Properties properties = new Properties();
properties.load(stream);
return properties;
} finally {
stream.close();
}
} catch (IOException exception) {
throw new RuntimeException("Could not load properties file");
}
}
});
}
return injector;
}
public static String getProperty(String propertyName) {
return getOrCreateInjector().getInstance(Key.get(String.class, Names.named(propertyName)));
}
}
Given the above code and file1.properties:
property1=Property1Value
property2=Property2Value
And file.properties:
property2=IncorrectProperty2Value
property3=Property3Value
with the provider
public class StringProvider implements Provider<String> {
private Properties properties1;
private Properties properties2;
private String propertyName;
public StringProvider(Properties properties1, Properties properties2,
String propertyName) {
this.properties1 = properties1;
this.properties2 = properties2;
this.propertyName = propertyName;
}
public String get() {
if(properties1.containsKey(propertyName)) {
return properties1.getProperty(propertyName);
}
return properties2.getProperty(propertyName);
}
}
The following usage:
public class InjectorFactoryTest {
public static void main(String ... parameters) {
System.out.println(InjectorFactory.getProperty("property1"));
System.out.println(InjectorFactory.getProperty("property2"));
System.out.println(InjectorFactory.getProperty("property3"));
}
}
Outputs:
Property1Value
Property2Value
Property3Value
Is there a way to override Spring Boot's PropertySourcesPropertyResolver and extend Externalize configuration by adding additional property source?
What I'm trying to do is to add another property source in the current list, and be able to override this property with current mechanism.
And to extend PropertySourcesPropertyResolver, so when Spring is mapping properties for classes annotated with #ConfigurationProperties
and requesting for the key, it can check for key with two different prefixes.
For example, if I have properties from two different locations:
Properties on location 1:
data.user=userName
Properties on location 2:
service.data.user=serviceUserName
I want to be able to override the value of data.user with a value of service.data.user (if that property exists).
Just to share with others, maybe someone finds this useful.
The Entire solution is related with bean which extends PropertySourcesPlaceholderConfigurer.
Part is to add another property source to the existing list of property sources.
In my case I needed application.property which is stored in some jar file.
For that purpose, we have JarPropertiesPropertySource:
public class JarPropertiesPropertySource extends MapPropertySource implements Logger {
#SuppressWarnings({"unchecked", "rawtypes"})
public JarPropertiesPropertySource(String name, Properties source) {
super(name, (Map) source);
}
protected JarPropertiesPropertySource(String name, Map<String, Object> source) {
super(name, source);
}
}
And the main logic is in CustomPropertySourcesPlaceholderConfigurer bean:
public class CustomPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer implements Logger {
#Override
public PropertySources getAppliedPropertySources() throws IllegalStateException {
final MutablePropertySources mps = new MutablePropertySources();
// Get existing PropertySources
PropertySources ps = super.getAppliedPropertySources();
ps.forEach(propSource -> mps.addLast(new PropertySourceProxy(propSource)));
// Add JAR property source
mps.addLast(new JarPropertiesPropertySource("jar", ....))
return mps;
}
}
We need to support property key overloading. For example, if we have property 'serviceA|data.user', and if that property doesn't exist then try to find property 'data/user'.
For that purpose, we need to proxy property sources, and each property from super.getAppliedPropertySources() wrap inside proxy PropertySourceProxy. So each spring call for getProperty will go through proxy method and check variations:
.
public class PropertySourceProxy extends PropertySource {
public PropertySourceProxy(PropertySource propertySource) {
super(propertySource.getName(), propertySource.getSource());
Object o = propertySource.getSource();
if (o instanceof StandardEnvironment) {
ConfigurableEnvironment ce = (ConfigurableEnvironment) o;
MutablePropertySources cemps = ce.getPropertySources();
cemps.forEach(propSource -> {
cemps.replace(propSource.getName(), new PropertySourceProxy(propSource));
});
}
}
#Override
public Object getProperty(String name) {
Object value = null;
if (name != null) {
int index = name.indexOf("|");
if (index != -1) {
String newName = name.substring(index + 1);
value = super.getProperty(newName);
}
}
if (value == null)
value = super.getProperty(name);
return value;
}
}
from: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.html#DEFAULT_VALUE_SEPARATOR
Example XML property with default value:
<property name="url" value="jdbc:${dbname:defaultdb}"/>
However, there appear to be a few people who have been having problems with multiple property placeholders, so you might want to watch out for:
Is there a way to specify a default property value in Spring XML?
property not found with multiple context:property-placeholder
The other way you could do it is to provide a default value for your data.user property and let people override it as necessary.
I would like to have a properties setup which can, on certain environments, override specific properties. For example, our default JDBC properties for dev are:
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/ourdb
db.username=root
db.password=
The problem is that some of our devs would like to have a different username/password on the db, or possibly even a non locally hosted db. The same is true for our rabbitMQ configuration, which currently uses a similar localhost, guest/guest setup. Being able to override the properties of certain elements of this configuration on a per-developer basis would allow us to move much of the infrastructure/installation requirements for building the software off the local machine and onto dedicated servers.
I have set-up a simple project to wrap my head around the configuration required to achieve what I want, and this is my first foray into the world of spring property configuration, since up till now, property loading and management is done with some custom code. Here is my setup:
class Main_PropertyTest {
public static void main(String[] args) {
String environment = System.getenv("APPLICATION_ENVIRONMENT"); // Environment, for example: "dev"
String subEnvironment = System.getenv("APPLICATION_SUB_ENVIRONMENT"); // Developer name, for example: "joe.bloggs"
System.setProperty("spring.profiles.active", environment);
System.setProperty("spring.profiles.sub", subEnvironment);
try(AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PropertyTestConfiguration.class)) {
Main_PropertyTest main = context.getBean(Main_PropertyTest.class);
main.printProperty();
}
}
private final String property;
public Main_PropertyTest(String property) {
this.property = property;
}
public void printProperty() {
System.out.println("And the property is: '" + property + "'.");
}
}
And my configuration:
#Configuration
public class PropertyTestConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer primaryPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.active") + ".main.properties"));
return propertySourcesPlaceholderConfigurer;
}
#Bean
public static PropertySourcesPlaceholderConfigurer secondaryPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(new ClassPathResource(System.getProperty("spring.profiles.sub") + ".main.properties"));
propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
propertySourcesPlaceholderConfigurer.setOrder(-1);
return propertySourcesPlaceholderConfigurer;
}
#Bean
public Main_PropertyTest main_PropertyTest(#Value("${main.property}") String property) {
Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property);
return main_PropertyTest;
}
}
And for completeness, my dev.main.properties and test.main.properties:
main.property=dev
main.property=test
The main problem is that I get an illegal argument exception. As far as I can tell, what I have written should be the javaconfig equivalent of this method: http://taidevcouk.wordpress.com/2013/07/04/overriding-a-packaged-spring-application-properties-file-via-an-external-file/
Unfortunately I get the following error: java.lang.IllegalArgumentException: Could not resolve placeholder 'main.property' in string value "${main.property}". Note that I also need to take care of the case where there is no sub-environment, and this is the case I have started with (although I get the same error even if both files exist). If I remove the bean which sets up the second propertysourcesplaceholderconfigurer, then it all works fine (by which I mean dev.main.properties is loaded and "And the property is: 'dev'." is printed out).
A secondary problem is that the code doesn't look great, and each layer of the system will need two PSPC's set-up so that they can access these properties. Furthermore, it requires a lot of manual calls to System.getProperty(), since I couldn't pass ${spring.profiles.active} to PSPC.setLocation();
Note: I have tried #PropertySources({primaryproperties, secondaryProperties}), but this fails because secondaryProperties does not exist. I have also tried #Autowired Environment environment; and getting the properties from that, but the secondary PSPC causes the environment to not be autowired...
So following this lengthy explanation, my questions are:
Is this the right way of solving this problem?
If so, what is wrong with my configuration?
How can I simplify the configuration (if at all)?
Is there an alternative mechanism available which would solve my problem?
Thank you for your time! :)
Your configuration is flawed when configuring BeanFactoryPostProcessor with java config the methods should be static. However it can be even easier, instead of registering your own PropertySourcesPlaceholderConfigurer utilize the default #PropertySource support.
Rewerite your jav config to the following
#Configuration
#PropertySource(name="main", value= "${spring.profiles.active}.main.properties")
public class PropertyTestConfiguration {
#Autowired
private Environment env;
#PostConstruct
public void initialize() {
String resource = env.getProperty("spring.profiles.sub") +".main.properties";
Resource props = new ClassPathResource(resource);
if (env instanceof ConfigurableEnvironment && props.exists()) {
MutablePropertySources sources = ((ConfigurableEnvironment) env).getPropertySources();
sources.addBefore("main", new ResourcePropertySource(props));
}
}
#Bean
public Main_PropertyTest main_PropertyTest(#Value("${main.property}") String property) {
Main_PropertyTest main_PropertyTest = new Main_PropertyTest(property);
return main_PropertyTest;
}
}
This should first load the dev.main.properties and additionally the test.main.properties which will override the earlier loaded properties (when filled ofcourse).
I had a similar issue with overwriting already existing properties in integration tests
I came up with this solution:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {
SomeProdConfig.class,
MyWebTest.TestConfig.class
})
#WebIntegrationTest
public class MyWebTest {
#Configuration
public static class TestConfig {
#Inject
private Environment env;
#PostConstruct
public void overwriteProperties() throws Exception {
final Map<String,Object> systemProperties = ((ConfigurableEnvironment) env)
.getSystemProperties();
systemProperties.put("some.prop", "test.value");
}
}
I'm trying to dynamically access properties from Spring's Environment property abstraction.
I declare my property files like this:
<context:property-placeholder
location="classpath:server.common.properties,
classpath:server.${my-environment}.properties" />
In my property file server.test.properties, I define the following:
myKey=foo
Then, given the following code:
#Component
public class PropertyTest {
#Value("${myKey}")
private String propertyValue;
#Autowired
private PropertyResolver propertyResolver;
public function test() {
String fromResolver = propertyResolver.getProperty("myKey");
}
}
When I run this code, I end up with propertyValue='foo', but fromResolver=null;
Receiving propertyValue indicates that the properties are being read, (and I know this from other parts of my code). However, attempting to look them up dynamically is failing.
Why? How can I dynamically look up property values, without having to use #Value?
Simply adding a <context:property-placeholder/> doesn't add a new PropertySource to the Environment. If you read the article you linked completely, you'll see it suggests registering an ApplicationContextInitializer in order to add new PropertySources so they'll be available in the way you're trying to use them.
To get this to work I had to split out the reading of the properties into a #Configuration bean, as shown here.
Here's the complete example:
#Configuration
#PropertySource("classpath:/server.${env}.properties")
public class AngularEnvironmentModuleConfiguration {
private static final String PROPERTY_LIST_NAME = "angular.environment.properties";
#Autowired
private Environment environment;
#Bean(name="angularEnvironmentProperties")
public Map<String,String> getAngularEnvironmentProperties()
{
String propertiesToInclude = environment.getProperty(PROPERTY_LIST_NAME, "");
String[] propertyNames = StringUtils.split(propertiesToInclude, ",");
Map<String,String> properties = Maps.newHashMap();
for (String propertyName : propertyNames)
{
String propertyValue = environment.getProperty(propertyName);
properties.put(propertyName, propertyValue);
}
return properties;
}
}
The set of properties are then injected elsewhere, to be consumed.