Is it possible to have multiple PropertyPlaceHolderConfigurer in my applicationContext? - java

I need to load a specific applicationContext.xml file according to a given system property. This itself loads a file with the actual configuration. Therefore I need two PropertyPlaceHolderConfigurer, one which resolves the system param, and the other one within the actual configuration.
Any ideas how to do this?

Yes you can do more than one. Be sure to set ignoreUnresolvablePlaceholders so that the first will ignore any placeholders that it can't resolve.
<bean id="ppConfig1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath*:/my.properties</value>
</list>
</property>
</bean>
<bean id="ppConfig2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="locations">
<list>
<value>classpath*:/myOther.properties</value>
</list>
</property>
</bean>
Depending on your application, you should investigate systemPropertiesMode, it allows you to load properties from a file, but allow the system properties to override values in the property file if set.

Another solution is to use placeholderPrefix property of PropertyPlaceholderConfigurer. You specify it for the second (third, fourth...) configurer, and then prefix all your corresponding placeholders, thus there will be no conflict.
<bean id="mySecondConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:/myprops.properties"
p:placeholderPrefix="myprefix-"/>
<bean class="com.mycompany.MyClass" p:myprop="${myprefix-value.from.myprops}"/>

Beware -- there might be a bug related to multiple configurers. See http://jira.spring.io/browse/SPR-5719 for more details.
I'm unable to get multiple to work locally... but I'm not yet blaming anyone but myself.

On my own side, playing with PropertyPlaceholderConfigurer both properties :
order (should be lower for first accessed/parsed PPC)
ignoreUnresolvablePlaceholders ("false" for first accessed/parsed PPC, "true" for next one)
and also give 2 distinct id(s) to both PPC (to avoid one to be overwritten by the other)
works perfectly
Hope it helps

You can't do this directly, and this JIRA issue from Spring explains why (check the comment from Chris Beams for a detailed explanation):
https://jira.springsource.org/browse/SPR-6428
However, he does provide a workaround using Spring 3.1 or later, which is to use the PropertySourcesPlaceholderConfigurer class instead of PropertyPlaceholderConfigurer class.
You can download a Maven-based project that demonstrates the problem and the solution from the Spring framework issues github:
https://github.com/SpringSource/spring-framework-issues
Look for the issue number, SPR-6428, in the downloaded projects.

We have the following approach working:
<util:properties id="defaultProperties">
<prop key="stand.name">DEV</prop>
<prop key="host">localhost</prop>
</util:properties>
<context:property-placeholder
location="file:${app.properties.path:app.properties}"
properties-ref="defaultProperties"/>
System property app.properties.path can be used to override path to config file.
And application bundles some default values for placeholders that cannot be defined with defaults in common modules.

Just giving 2 distinct ids worked for me. I am using spring 3.0.4.
Hope that helps.

In case, you need to define two PPC's (like in my situation) and use them independently. By setting property placeholderPrefix, you can retrieve values from desired PPC. This will be handy when both set of PPC's properties has same keys, and if you don't use this the property of ppc2 will override ppc1.
Defining your xml:
<bean name="ppc1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props1" />
<property name="placeholderPrefix" value="$prefix1-{" />
</bean>
<bean name="ppc2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props2" />
<property name="placeholderPrefix" value="$prefix2-{" />
</bean>
Retrieving during Run time:
#Value(value = "$prefix1-{name}")
private String myPropValue1;
#Value(value = "$prefix2-{name}")
private String myPropValue2;

Related

How to change spring bean property value in xml at runtime?

I have a springconfig.xml file and i used to get the bean property values from my.properties file. property file values are changed dynamically. but it will not set to the spring bean property. it will change only after i restart my tomcat. Here is my part of xml code.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:/SATHISH/apache.8.0.24/bin/my.properties</value>
</property>
</bean>
<bean id="jmsEmailTemplateBean" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="authenticationConnectionFactory" />
<property name="defaultDestination" ref="${queuename}" />
</bean>
if i change the my.properties value to "foo" it will work.
again i change "foo" to "boo" at runtime it will not work. It will not assign to ${queuename}.
manually i changed my.properties value at runtime. it will not affect springconfig.xml
It is possible to change xml values at runtime?
Thanks in advance
You'd need to watch the file programmatically in order to reload the changes or use this bean org.springframework.context.support.ReloadableResourceBundleMessageSource
to reload properties file.
Try using SpringBoot or IntelliJ Idea ;)

How to properly load multiple properties file in Spring from different locations?

As I can see there were plenty questions regarding properties in Spring already asked, but what I want to achieve is a little unusal.
Let assume that I have cp.prop.file.properties on the classpath
external.prop.file.path=file:./path/to/external.prop.file.properties
Now if in my spring context I will declare something like this
<context:property-placeholder location="classpath:cp.prop.file.properties" />
<context:property-placeholder location="${external.prop.file.path}" />
I suppose it will not work properly. I do not have possibility to check at the moment.
I believe my intentions on what I am trying to achive are fairly clear. In general, I want to have some properties that are build dependet and are not configurable and some that configurable and are externalized. And the path to the latter is defined during build.
You can load more than one property file with following syntax
<context:property-placeholder
location="classpath:a.properties, file:/path/to/myConfigFile.properties"
ignore-unresolvable="true"/>
Use on from following solution
<context:property-placeholder
location="classpath:core-application.properties,
classpath:core-services.properties,
classpath:core-messages.properties"
ignore-unresolvable="true"/>
or
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:core-application.properties</value>
<value>classpath:core-services.properties</value>
<value>classpath:core-messages.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
We can define multiple properties files using XML configuration with this:
<context:property-placeholder location="classpath:foo.properties, ${external.prop.file.path}"/>
If we use JavaConfig wen can use this (Java 8 and onwards):
#PropertySource("classpath:foo.properties")
#PropertySource("${external.prop.file.path}")
public class PropertiesWithJavaConfig {
//...
}
Or this (previous to Java 8):
#PropertySources({
#PropertySource("classpath:foo.properties"),
#PropertySource("${external.prop.file.path}")
})
public class PropertiesWithJavaConfig {
//...
}
BTW, in the event of a property name collision, the last source read takes precedence.
More info here, here and here.

How to reference an ${ENV} var in a propertyConfigurer bean?

I'm trying to modify this example for my own purposes.
I want to load the properties from a server-specific file, using something like this:
<beans:bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="locations">
<beans:list>
<beans:value>${ENV_JDBC_CONFIG}</beans:value>
</beans:list>
</beans:property>
</beans:bean>
Where ENV_JDBC_CONFIG is an enrivonment variable specifying a path to a properties file.
This fails with
`java.io.FileNotFoundException: Could not open ServletContext resource [/${ENV_JDBC_CONFIG}]`
How can I accomplish what I'm trying to do here?
Use systemPropertiesMode property of the configurer to use System properties.
check this article, it tells you tips to manage external properties.
If you want to use env variable inside other bean definition you could use it like
<bean id="yourBean" class="com.company.YourBean">
<property name="environment" value="#{ systemProperties['env.var1'] }"/>
<!-- other properties goes here....-->
</bean>
Spring throws a misleading error message when the variable referenced in ${} is not defined.
In this case it told me FileNotFound when in fact the variable was not defined (with that exact spelling, anyway).
The fix was to add -DENV_JDBC_CONFIG=file:/blah/blah/blah in /etc/defaults/tomcat7

How to externalize links in a spring frame work

I have to externalize a couple of links in my application. The links have to be in a properties file which can be changed without the need for a build and deploy. I tried adding values in the server.properties of my jboss and using that variable in my controller but i am unable to get a value.
How do i go about this?
Using ResourceBundle
ResourceBundle bundle = ResourceBundle.getBundle("<myfile>");
String studentName = bundle.getString("<property-name>");
If you put the values in server.properties, then configure PropertyPlaceholderConfigurer in your applicationContext, something like this:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:server.properties</value>
</property>
</bean>
or the shorter Spring 3 version:
<context:property-placeholder location="classpath:server.properties"/>
and then just inject the values you need to your beans with
<bean id="someBean">
<property name="myProperty" value="${this.is.property.from.server.properties}" />
</bean>
or with #Value annotation like
#Value("${this.is.property.from.server.properties}")
private String myProperty;

"Recycling" names within a spring application context

lets say, I have a lot of stuff within my spring application context which looks like that
<bean name="foo.0001" class="com.example.MyClass">
<property name="name" value="foo.name.0001"/>
<property name="zap">
<bean class="com.example.Other">
<property name="name" value="foo.name.0001"/>
</bean>
</property>
<property name="bar">
<bean class="com.example.NextOther">
<property name="name" value="foo.name.0001"/>
</bean>
</property>
</bean>
so the string foo.name.0001 appears within the bean definition several times. Because it is a larger system with several blocks of this configuration, it is quite annoying to modify each of those ids. Ideally I would want to set it only once within a block. Is there a possibility to set some kind of property which exists only in a local scope of a bean definition?
I'm not sure how that would logically work, as you would still have to reference that value somehow to pass it to the nested beans. If you are worried about defining it multiple times, you can have a look at Springs PropertyPlaceholderConfigurer. It will allow you to the following:
<property name="bar">
<bean class="com.example.NextOther">
<property name="name" value="${foo.name.001}"/>
</bean>
</property>
This would allow you to define it once, and reference it from multiple locations.
It depends how much effort you want to put into to this but your requirements could be fufilled by a spring custom namespace. These are ideal when you have lots of identical blocks of beans each configured differently.
Basically you'd define the xml schema then write a bean definition parser that sets up the beans as required.
See here for more details:
http://www.javaworld.com/javaworld/jw-02-2008/jw-02-springcomponents.html
This is how Spring security simplified its xml configuration.

Categories