difference in behaviour between spring PropertyPlaceholderconfigurer and PropertyOverrideConfigurer - spring

I wanted to externalize my configuration properties so planned to use - PropertyPlaceholderconfigurer - here is my context file:
<bean id="helloBean" class="com.springex1.HelloWorld">
<property name="name" value="test!{my.db.jdbc.driver}" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="testPropertyConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="location" value="classpath:/springdb.properties"/>
<property name="placeholderPrefix" value="test!{"/>
<property name="placeholderSuffix" value="}"/>
<property name="order" value="0"/>
</bean>
Simple java class - HelloWorld.java
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void printHello() {
System.out.println("Hello ! " + name);
}
My properties file:
my.db.jdbc.driver=xyz
foo=bar
All of this works fine. Note that the first property is being injected
my.db.jdbc.driver=xyz
while the second property
foo=bar
is not being used - but spring works fine and does not complain
Now I decided to override the properties - so decided to add the propertyOverrideConfigurer
<bean id="propertyOverrideConfigurer"
class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="location" value="classpath:/override.properties" />
<property name="order" value="20" />
</bean>
Added the override.properties:
helloBean.name=oracle.jdbc.OracleDriver
This works as expected and prints - oracle.jdbc.OracleDriver
Now my understanding was that I wanted to override the additional property
foo=baz
And then code failed :
Exception in thread "main" org.springframework.beans.factory.BeanInitializationException: Could not process key 'foo' in PropertyOverrideConfigurer; nested exception is org.springframework.beans.factory.BeanInitializationException: Invalid key 'foo': expected 'beanName.property'
This part is understood - spring is looking for bean name 'helloBean' and then its corresponding attribute.
While the issue is understood - my question is - in PropertyPlaceholderConfigurer I can define additional properties which are not injected and it works fine.
But - PropertyOverrideConfigurer - any property defined must get injected and for that to happen - there must be a bean with attributes available
I cannot really have additional properties hanging around in case of PropertyOverrideConfigurer - which does not sound right.
am I missing something that can ignore this error ?

Related

How to get key value from properties file at runtime using spring

I want to get the changed key value from properties file at runtime.
test.properties file:
name = Hi
I have made Thread sleep with 5 sec and changed the key value as "Hello" but it is not getting changed.
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:test.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:test</value>
</list>
</property>
<property name="cacheSeconds" value="1" />
</bean>
<bean id="tempBean" name="tempBean1" class="org.sri.spring.temp.Temp"
lazy-init="false" scope="prototype">
<constructor-arg type="String" value="${name}" />
</bean>
The ${name} placeholder inside the XML configuration is resolved using the PropertySourcesPlaceholderConfigurer which, as you may notice, has nothing in common with your reloadable messageSource.
It wouldn't work either way because Spring instantiates the tempBean only once: on application startup, by passing the value of ${name} to the constructor. The bean itself is not aware of where the value came from (and in particular, it doesn't care if the properties file gets edited).
If you really think it's a good idea to do it†, you can inject the entire messageSource into your tempBean, and get the current value in each call, e.g.:
public class Temp {
#Autowired // or wired in XML, constructor, etc.
private MessageSource messages;
public String sayHello() {
return messages.getMessage("name", null, Locale.getDefault());
}
}
† injecting a configuration-related object makes testing more difficult and is arguably bad design (mixing concerns). Have a look at the Spring Cloud Config project as it's likely that this is how the future is going to look like.
I do not think that Spring will update already existing beans when the properties change.
Try to create a new bean (prototype scope)

spring bean initializing instances differently via property wiring

I have the following properties in a property file:
context1.property1=value1
context1.property2=value2
context1.property3=value3
context2.property1=value4
context2.property2=value5
context2.property3=value6
I have a bean with the following structure:
class Bean {
private property1;
private property2;
private property3;
}
Is there any way better to initialize 2 instances of Bean without writing something like:
<bean id="bean1" class="com.test.Bean">
<property name="property1" value="${context1.value1}" />
<property name="property2" value="${context1.value2}" />
<property name="property3" value="${context1.value3}" />
</bean>
<bean id="bean2" class="com.test.Bean">
<property name="property1" value="${context2.value1}" />
<property name="property2" value="${context2.value2}" />
<property name="property3" value="${context2.value3}" />
</bean>
Thanks!
Have a look at PropertyOverrideConfigurer:
Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions.
Configuration lines are expected to be of the following form:
beanName.property=value
Example properties file:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
See also
Using PropertyOverrideConfigurer with Annotated Classes in Spring 3

Dynamically loading SpringBean by environment var

I'm trying to figure out the best way to load a spring bean, depending on a system environment variable being set. I realize that this would be a simple task using profiles, but unfortunately I'm using Spring 2.5. So here is the bean definition in my XML file:
<bean id="updateBlogEntryListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destinationName" value="queue/updateBlogEntryQueue"/>
<property name="messageListener" ref="updateBlogEntryMessageHandler"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="sessionTransacted" value="true"/>
<property name="destinationResolver" ref="destinationResolver"/>
</bean>
Basically, I'm looking for a way to only load that bean based on the existence of a system environment variable, otherwise, ignore it. I've been looking into the use of BeanPostProcessors and BeanFactoryPostProcessors, but can't quite put my finger on the solution. Any help on this would be greatly appreciated. Thanks!
You could implement a FactoryBean that would check the environment variable and create the actual bean or some NoOp implementation - returning a null from the FactoryBean might also work if it is not referenced anywhere.
class ListenerContainerFactory extends FactoryBean<MessageListenerContainer> {
MessageListenerContainer getObject() {
if (someCondition) {
// create and return DefaultMessageListenerContainer
} else {
// return null or some NoOpMessageListenerContainer
}
}
}

Does order matter while injecting properties in ProxyFactoryBean

I am trying to inject the aspects in a service. For this service I am creating a proxied object using classic way.
I have written a bean- baseProxy of type (ProxyFactoryBean) which contains a list of all the required advices.
<bean id="baseProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>methodInvocationAdvice</value>
</list>
</property>
</bean>
I am creating a proxy for the service like this :
<bean id="singproxy" parent="baseProxy">
<property name="target" ref="singtarget" />
<property name="targetClass" value="com.spring.learning.SingingService"></property>
</bean>
Which doesn't work but when I revert these two properties and write like this :
<bean id="singproxy" parent="baseProxy">
<property name="targetClass" value="com.spring.learning.SingingService"></property>
<property name="target" ref="singtarget" />
</bean>
To my surprise it works fine. In spring does it matter on the order for bean ? Or its a special case with ProxyFactoryBean?
I tried with Spring 3.0 I am not sure same behavior exists with previous versions.
Concerning target and targetClass, It's one or the other, but not both. Here's the relevant source (from org.springframework.aop.framework.AdvisedSupport), a parent class of ProxyFactoryBean:
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
public void setTargetSource(TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
public void setTargetClass(Class targetClass) {
this.targetSource = EmptyTargetSource.forClass(targetClass);
}
As you can see, both setTarget() and setTargetClass() write to the same field, so the last assignment wins.

How do you acess a property of a bean for reading in a spring xml config file?

I want to do something like the following in spring:
<beans>
...
<bean id="bean1" ... />
<bean id="bean2">
<property name="propName" value="bean1.foo" />
...
I would think that this would access the getFoo() method of bean1 and call the setPropName() method of bean2, but this doesn't seem to work.
What I understood:
You have a bean (bean1) with a
property called "foo"
You have another bean (bean2) with a
property named "propName", wich also
has to have the same "foo" that in
bean1.
why not doing this:
<beans>
...
<bean id="foo" class="foopackage.foo"/>
<bean id="bean1" class="foopackage.bean1">
<property name="foo" ref="foo"/>
</bean>
<bean id="bean2" class="foopackage.bean2">
<property name="propName" ref="foo"/>
</bean>
....
</beans>
Doing this, your bean2 is not coupled to bean1 like in your example. You can change bean1 and bean2 without affecting each other.
If you REALLY need to do the injection you proposed, you can use:
<util:property-path id="propName" path="bean1.foo"/>
You need to use PropertyPathFactoryBean:
<bean id="bean2" depends-on="bean1">
<property name="propName">
<bean class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetBeanName" value="bean1"/>
<property name="propertyPath" value="foo"/>
</bean>
</property>
</bean>
I think you have to inject bean1, then get foo manually because of a timing issue. When does the framework resolve the value of the target bean?
You could create a pointer bean and configure that.
class SpringRef {
private String targetProperty;
private Object targetBean;
//getters/setters
public Object getValue() {
//resolve the value of the targetProperty on targetBean.
}
}
Common-BeanUtils should be helpful.

Resources