I'm using Spring 3.0.5
I have a #ManagedResource bean, for some of the #ManagedAttribute methods which I want to set a defaultValue. Instead of setting it to a hardcoded value I want to be able to read it from a property value at load time, since the default changes from environment to environment.
A snippet from my programs applicationContext.xml:
<context:mbean-export default-domain="sampleApp"/>
<bean id="managedBean" class="com.example.sampleBean">
<constructor-arg value="Sample Bean"/>
<constructor-arg value="${sample.property}"/>
</bean>
I believe I have to use the XML configuration to be able to do this, but haven't figured out how to do it yet.
You can add the following to your applicationContext.xml, it should expose the properties you are after:
<context:property-placeholder location="classpath:application.properties"/>
So if the application.properties file you are pointing to above contains a property called sample.property then Spring will use that to inject into your ${sample.property} placeholder.
For more details you can see the Spring reference here.
Related
I wonder if there is a way to extract properties from Spring Environment (e.g. obtained from ApplicationContext) in the form of Properties instance? Or, at least, is there a way to enumerate the properties in Spring Environment, or get them all as a map, or any other way I can turn a [initially unknown] set of properties into a Properties object?
I need this in order to create a jclouds Context by calling org.jclouds.ContextBuilder.newBuilder() and .overrides(Properties). The idea is to configure the actual cloud provider solely by means of .properties file, and I don't want to couple application logic with provider-specific properties.
[UPDATE]
The .properties files to be used are configured using <context:property-placeholder>, and it actually specifies a list of paths, like this:
< context:property-placeholder location=
"classpath:/jdbc.properties,
file:${jboss.server.config.dir}/jdbc.properties,
file:${catalina.home}/conf/jdbc.properties"
ignore-resource-not-found="true"/>
which suggests that the .properties file is searched in the mentioned list of locations in order. I would like to achieve the following:
keep the list of .properties files and their possible locations in this XML definition file only;
allow to place jclouds related properties in any of the .properties files mentioned in the XML;
access the properties, resolved and loaded by Spring, in the form of Properties object so I am able to feed that to jclouds ContextBuilder.
Please let me know if all of this is feasible. Thank you in advance!
-Vlad
If you wan't to use properties in your Spring configuration then you can simply use:
<context:property-placeholder location="classpath:foo.properties" />
To get the properties in your code later you can simply read this file from the classpath into a Properties object:
props.load(MyClass.class.getClassLoader().getResourceAsStream("foo.properties"));
Alternatively you can have a look at PropertyPlaceholderConfigurer.
UPDATE
Updated after Deinum's remark but only if you are getting the properties from a Spring managed bean:
<util:properties id="myProps"
location="classpath:foo.properties"/>
<context:property-placeholder properties-ref="myProps" />
Now you can inject myProps into Spring managed beans (no need to load them again from the classpath).
You could use PropertiesFactoryBean and do something like this:
<bean id="jcloudsProps"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>your/props/file.properties</value>
</property>
</bean>
You can then use jcloudsProps as you would any other Spring bean.
I've got a Spring bean:
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="#{ config['app.name'] }"/>
</bean>
This bean is defined in a jar and used in two apps that both get deployed to the same tomcat server. I've only got one properties file the apps share and I'd like to keep it that way if possible. You might see the problem - I need two values for app.name (one for each web app).
I need to set the app.name independently in each app. I don't mind hard coding the value in the Java (but don't think I can inject the value in that direction). I know I can introduce another properties file at a different path and override but I'm hoping there is a better way I can accomplish this through Spring that will allow me to maintain only one shared properties file.
Possible solutions, in recommended order:
1 - is there a reason why the shared bean is declared in a separate jar file? Certainly, the bean class can be located there, but why not declare the actual bean inside the individual web apps where it's being used?
2 - if you absolutely need to keep the bean definition in the shared jar you can use bean inheritance; (a) change your bean class to use a property rather than a constructor arg:
<bean id="sharedBean" class="com.bean.SharedBean">
<property name="app-name" value="default"/>
</bean>
(b) in your web app context file:
<bean id="instanceBean" parent="sharedBean">
<property name="app-name" value="app1"/>
</bean>
3 - use a Spring profile; in your shared jar context.xml:
<beans profile="app1">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app1"/>
</bean>
</beans>
<beans profile="app2">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app2"/>
</bean>
</beans>
note: <beans profile=... MUST be the last entries in your context file.
Add a context param to each web.xml (changing value as appropriate):
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>app1</param-value>
</context-param>
I was wondering if there is any way that we can set the value of environment variable dynamically without restarting the server so that different property files might get accessed based on the value of currently set environment.
Consider these are my two property files:
config-dev.properties
config-prod.properties
Now since I have appended the name of environment with every file, so I want to know that is it possible that I dynamically change or set the value of environment name and the corresponding property file will be used without restarting the server.
I know how to set the env.name in configuration XML file.
<context:property-placeholder location="classpath:/config-${env.name}.properties>
I want to change the environment name programmatically so the correct property file can be used when it is accessed.
<context:property-placeholder location="classpath:/config-${env.name}.properties> is one way to do it. where your env.name is the run configuration can be the startup parameter you set.
Another way to do it is to use the Spring bean Profile. where you define a profile and the beans defined for those profile would be loaded during the Spring container startup.
<beans profile="dev">
<bean .... />
<context:property-placeholder
location="classpath:conf/properties/dev.properties" />
</beans>
<beans profile="prod">
<bean .... />
<context:property-placeholder
location="classpath:conf/properties/prod.properties" />
</beans>
I am not sure about changing it without restarting the server. since your Spring container has already started, and the beans are already loaded. now you do want to load a different set of beans without restarting the Spring container. I am not sure about that.
The basic reason for that according to me would be upon, how do you change the already autowired dependencies during runtime without affecting any other running application classes? What about a functionality which is being executed and you want to change the DB URL through the switch in the properties file? How do you control that?
I am using spring 3.1 with spring profiles to load the beans. In my app context file, I load the properties like :
<context:property-placeholder order="1" location="classpath*:META-INF/spring/*_${spring.profiles.active}.properties" ignore-unresolvable="true"/>
And then I use the property value to load the data source bean like
<property name="driverClassName" value="${database.driverClassName}"/>
It works fine.
The problem starts when I add a couple of more property placeholders so that properties from some database tables can be loaded.
This uses a properties reference loaded by
<bean id="configFactoryBean"
class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<constructor-arg ref="globalSystemConfiguration"/>
</bean>
To add to the details, this configFactoryBean uses the datasource to load the properties from the database.
When I do this, I have the following exception:
java.lang.ClassNotFoundException: ${database.driverClassName}
My analysis is that its trying to load the datasource before resolving the property from the first context property placeholder. I may be wrong. Or maybe spring profile variable is not resolved properly.
Can anyone please help me to fix this.
Thanks
Akki
This bug about multiple property placeholders might relate to your problem: https://jira.spring.io/browse/SPR-9989
When using multiple PropertyPlaceholderConfigurer in conjunction with
#Value annotation and default value for placeholders syntax (ie
${key:defaultValue}), only the first PropertyPlaceholderConfigurer is
used. If this configurer does not contain the desired value, it falls
back to #Value default even if the second
PropertyPlaceholderConfigurer contains the value.
Affects Version/s: 3.1.3
Each <context:property-placeholder> creates a new instance of PropertyPlaceholderConfigurer - it gets messy easily. You should have one such thing per application and on application level, not on libraries' one - that makes maintenance much easier.
For more details and a suggestion how to cope with it look here:
http://rostislav-matl.blogspot.cz/2013/06/resolving-properties-with-spring.html
In my application I am using property-placeholder configurer in following way and it works very well. You can try that.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
</list>
</property>
</bean>
I think this should resolve your problem. :)
Since you have suggested hardcoding the path to the configuration file works, try using the profiles attribute on the tag to selectively include the configuration.
<beans profile="profileName">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="profileName2">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
See this article explaining profiles: http://java.dzone.com/articles/using-spring-profiles-xml
I'm running tests using spring (SpringJUnit4ClassRunner and #ContextConfiguration). The tests are run in parallel.
Some of my beans are singleton, and I would like to change them to be in scope "thread" of the tests. I want each test to have its own instance of the bean.
I've managed to it by having an applicationContext.xml file and a applicationTestContext.xml file which is used for tests.
In the applicationTestContext.xml I define those beans with scope "thread".
The problem with this is that everytime we add a new bean of that type, we'll have to add it to both applicationContext.xml and applicationTestContext.xml which is pretty annoying.
Is there a way to do it with less boilerplate?
Gather up all the beans whose scope you want to customize and put them in a separate bean config file, included from both applicationContext and applicationTestContext, e.g.
<import resource="customScopedBeans.xml"/>
Then use a placeholder for the scope
<bean class="com.Foo" scope="${threadOrSingleton}" />
and declare the property differently in the parent config file.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>threadOrSingleton=thread</value>
</property>
</bean>