In spring 4.1.2.RELEASE, we have 2 active profiles in web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>Production,Customer1</param-value>
</context-param>
And we want to dynamically load some property files as below:
<util:properties id="accountPolicy"
location="classpath:/configs/${spring.profiles.active}/sample.properties" />
The ${spring.profiles.active} is not working, may be because there are two profiles, I tried some lookups like: ${spring.profiles.active[1]} but no luck !
Any comments
Updated:
It seems that ${spring.profiles.active} is an comma seperated list I try below:
<util:properties id="signConditions"
location="classpath:/configs/#{ {'${spring.profiles.active}'.split(',')}.get(1) }/sample.properties" />
But the error seems that there will be an XML parsser error:
org.springframework.expression.ParseException:
Expression 'classpath:/configs/#{ {'Production,Customer1'.split('' # 19: No ending suffix '}' for expression starting at character 19: #{ {'Production,Customer1'.split('
This did the job:
<util:properties id="signConditions"
location="classpath:/configs/#{environment.getActiveProfiles()[1]}/sample.properties" />
I believe the more proper way is to do something like:
<beans profile="Production">
<!-- some other stuff for Production profile -->
</beans>
<beans profile="Customer1">
<util:properties id="accountPolicy"
location="classpath:/configs/Customer1/sample.properties" />
<!-- some other stuff for Customer1 profile -->
</bean>
Profiles are supposed to be used as Profiles of configurations in app context, instead of like a property for replacement (as what you are doing)
Edit base on my comment:
What you are looking for is not a proper use case of Spring profile feature (at least not now). What you are trying to do is having property place holder work base on a system property. However, activation of profiles can be done through other way. Which means, you can turn on a profile without that spring.profiles.active system property. What you are doing is not reliable.
If it is fine for you to pass in system properties, why not do something like:
Have a profile called Customer, which denote for deployment to customers which will involve account policy (and other stuff)
Pass in a system property, for example, with key = 'customerCode' and value being an identifier for a customer.
By doing so, what you need to do is
<beans profile="Production">
<!-- some other stuff for Production profile -->
</beans>
<beans profile="Customer">
<util:properties id="accountPolicy"
location="classpath:/configs/${customerCode}/sample.properties" />
<!-- some other stuff for Customer1 profile -->
</bean>
and system properties you need for your application should looks like: -Dspring.profiles.active="Production,Customer" -DcustomerCode=Customer1
Then you have proper use of profiles, and no need to duplicate accountPolicy for each customer.
Related
I'm using spring-session + redis as documented here:
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/httpsession-xml.html
How can I configure RedisHttpSessionConfigure such that for local development, redis is not needed and the application will simply default to the container session handling?
Generally this isn't recommended because you are differing your development environment from your production environment. It should be quite trivial to point your dev machine to a Redis instance.
If you need to support it, you can use Spring profiles. For example, with XML you can use something like:
<beans profile="dev">
<bean id="springSessionRepositoryFilter" class="org.springframework.web.filter.CharacterEncodingFilter"/>
</beans>
<beans profile="production">
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"/>
</beans>
The key is to ensure that your dev environment also has a Bean that implements Filter named springSessionRepositoryFilter. In this example, I used CharacterEncodingFilter which should do nothing since the encoding property is not set but feel free to replace with whatever you like.
The next thing you will need to do is activate your environments. For example, you can use
-Dspring.profiles.active="production"
Is there anyway to specific the default profile directly in the Spring XML
<beans profile="Development">
<!-- Load Development beans -->
</beans>
<beans profile="Production">
<!-- Load Production beans -->
</beans>
Note, I don't want to do this programmatically, as command-line property, environment variable or web.xml (its not a web app)
I want to do it directly in the xml something like:
<property name="spring.profiles.default" value="Production">
I have a very common use case -- connect to different databases when my program is in development mode, in test mode, or in deployment mode.
The way I am doing it now, is I configure a data source, and pass it ${...} properties via bean:property tag.
However to get the ${...}, i am doing
<context:property-placeholder properties-ref="myProperties" />
and in the bottom of the xml config, I have
<beans profile=test>
<util:properties id=myProperties>
</util>
</beans>
<beans profile=dev,default>
<util:properties id=myProperties>
</beans>
<beans profile=prod>
<util:properties id="myProperties>
</beans>
This seems inefficient, overly verbose, and prone to error. All spring properties tutorials tell me that context:property-placeholder is Environment aware, and Environment is responsible for profiles so how do I simplify this? It is intuitive to me that there is a simpler way, I just can't figure it out.
Really, what I am looking for is to specify profile on context:properties-placeholder, or something like that.
I solved that problem once (a long time before Spring supports profiles): spring property substitution for test and production
nowadays a would still use property files but, but I would select them by profiles. There are a lot of ways to do this:
The simplest one is:
<context:property-placeholder
location="classpath*:META-INF/spring/config-${spring.profiles.active}.properties" />
an other is:
<beans profile="normal">
<context:property-placeholder
location="classpath*:META-INF/spring/config-normal.properties"/>
</beans>
<beans profile="test">
<context:property-placeholder
location="classpath*:META-INF/spring/config-test.properties"/>
</beans>
The first approach has the drawback, that when more than one profile is activated then only the properties for the first profile gets loaded. I am not sure what will happen with the second approach when having more than one profiles.
For the first approach I found this solution, but I have not tested it:
<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>
While profiles are certainly a solution to that problem I think that this approach opens another big door to issues that you discover only on the target platform.
In my projects I have always externalized the properties and turned as many properties as possible into runtime parameters.
Just imagine having to bundle Jenkins/Sonar/etc again as your platform will not be part of a profile with properties residing in the classpath. I don't think that then these would be successful projects ;)
As for spring you can use the 'file://' protocol in a propertyconfigurer allowing to superseed a "dedault" property coming from the classpath. So you have two configurer tags with an order parameter and other properties. Here's an example:
<jee:jndi-lookup id="configDirectory" jndi-name="configDirectory"
resource-ref="true" default-value="." />
<jee:jndi-lookup id="datasource" jndi-name="jdbc/datasource"
expected-type="javax.sql.DataSource" default-ref="localDatasource" />
<!-- Allows fetching properties from multiple locations: -->
<!-- external definition -> file://${configDirectory}/root-context.properties
-> declared in context.xml -->
<!-- standard web application bundle -> /WEB-INF/spring/root-context.properties -->
<!-- testing -> classpath:root-context.properties -->
<context:property-placeholder location="${configDirectory:.}/context.properties"
order="9" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder
location="/WEB-INF/spring/context.properties,
classpath:context.properties"
order="10" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder location="classpath:spring/default.properties"
order="100" />
Like this we are able to build it locally, run our unit and integration tests during maven build, run the build on UAT and if all that is ok copy the build from UAT to PROD without having to modify the war file.
In the properties we define all the parametersthat cannot be changed at runtime, which is essentially the Hibernate parameters plus some others.
All the rest is stored in the database as simple system parameters (key-value pairs). There are a lot of properties that do not need to be fixed. This includes: LDAP, MailSender, folder definitons like tempdir and others.
As the datasource is one of the very first beans to be initiated this works pretty nice in the projects I am running currently, and we are still discovering more properties to be pushed into the database.
Please read:
https://examples.javacodegeeks.com/enterprise-java/spring/load-environment-configurations-and-properties-with-spring-example/
<context:property-placeholder location="
classpath:application.properties,
classpath:application${spring.profiles.active}.properties"
ignore-unresolvable="true"/>
mvn clean install -Dspring.profiles.active="profile_name".
I would like to do a SPRING (3.2.1) setup where I can switch the underlying JMS provider depending on the environment you are in e.g. dev, test, prod. I am no expert but have come across #Profile annotation of Spring. I don't really know how to use it. So what I need to do is in DEV environment I want to use ActiveMQ and in PRODUCTION I want to use IBM MQ. Is this possible? If so, would appreciate it if you could provide some config or code to do this. Thanks in advance.
http://static.springsource.org/spring-framework/docs/3.2.1.RELEASE/spring-framework-reference/html/new-in-3.1.html#new-in-3.1-bean-definition-profiles
For XML config, see this blog... http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
See this blog about #Profile: http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/ for using profiles with #Configuration.
It boils down to this...
When using XML configuration, simply add <beans/> elements at the end of your spring config files...
<beans ...>
<bean... />
<beans profile="DEV">
<bean ... // my ActiveMQ config .../>
</beans?
<beans profile="default">
<bean ... // my IBM (or JNDI) config .../>
<beans/>
</beans>
Then run in dev with -Dspring-profiles-active=DEV.
Similarly #Profile can be added to #Configuration classes to limit their use to particular active profiles.
is it possible to define in a spring context file, and one or more properties that
can be accessed in <bean> elements.
The example below illustrates best what I need - I want to define the property FOO once and then reference it multiple times in my various <bean> definitions:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<properties>
<property name="FOO" value="BAR">
</properties>
<bean name="TEST" class="mytest">
<property name="MYFOO" value="${FOO}"/>
</bean>
<bean name="TEST1" class="mytest1">
<property name="MYFOO" value="${FOO}"/>
</bean>
</beans>
Any input would be much appreciated.
Thanks, Kevin.
You can do this using the snappily-named PropertyPlaceHolderConfigurer. See here for the example in the spring docs. You don't define the property values themselves in the spring beans file, you externalise them in a .properties file.
You could, I suspect, use PropertyPlaceHolderConfigurer or one of its siblings to inject a Properties object defined inside your Spring file, but that would be a rather more verbose solution.
If you only need to define them in your xml file and never change them (like you would change a configuration option, say a port or an ip), you can create a bean of class String with the given property and then write . Creating a bean of class String isn't the most straight forward thing, but it's doable.
If you want something more complicated (say you want a configuration file residing outside the jar where your xml with the bean definition is), you can look at the PropertyPlaceholderConfigurer class.
Just found a way to do this all in the spring XML file with no external properties file needed (though you can supplement with one if desired)
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<util:properties>
<prop key="foo1">bar1</prop>
<prop key="foo2">bar2</prop>
</util:properties>
</property>
</bean>
then you reference them just like normal as ${foo1} where needed