Spring approach for changing configuration source by environment - spring

I'm new to Spring and trying to figure out the best way to handle the following scenario:
We have an application where for local development and testing, all configuration values are pulled from a Properties file. When the app is deployed on to the App Server (Websphere in this case), instead of properties file we use JNDI resource properties.
Is there an accepted way of handling this in Spring? For a non-Spring application I probably would have done something like this using a good ol' factory pattern to decide the config source. For Spring, I've seen examples that use different context XML files per environment (sounds messy), or make use of Spring "Profiles".
Is there a generally accepted practice for this scenario?

Spring profiles are rather new and they were added precisely to address your problems. Moreover they should deprecate all other workarounds like different context XML files you mention.
For the sake of completeness here is an example:
<beans profile="test">
<context:property-placeholder location="/foo/bar/buzz.properties" />
</beans>
<beans profile="prd">
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name"/>
</beans>
Depending on which profile you choose during deployment/startup, only one of the beans above will be instantiated.
Another approach I've never tried but seems to fit your case is default-value attribute in jee namespace:
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name" resource-ref="true"
default-value="classpath:foo.properties"/>
Not sure if this will help you though.

Assuming Spring 3.1, try using profiles like Tomasz suggested, but instead of setting individual JNDI values for production, use
<beans profile="prd">
<context:property-placeholder/>
</beans>
In Spring 3.1, ContextLoaderListener apparently pulls in JNDI props as a PropertySource by default, so with property-placeholder, when you need to access a value you can just use ${some/jndi/name} in applicationContext.xml or a #Value annotation.
To make sure the webapp gets the values from JNDI, add
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prd</param-value>
</context-param>
to web.xml.
In your tests, set the system property 'spring.profiles.active' to 'test', and you'll get the values from the props file.

one way to go is you use jndi also for local dev and testing. You could define the same jndi name. I don't know what's your testing server, in practice we use jetty, and maven-jetty plugin to test. It is lightweight and can run from your ide.
another way is like what you said in your question. Making use of Spring profile. Then you could declare different transactionManager beans with same id/name. of course they should be in different profiles. At runtime you could decide which profile should be activated, that is, which bean should be used.

Related

Alternative to spring profiles

Using spring 3 I can determine which bean to use at runtime. But using Spring 2.5 what is the alternative?
Here is the config within my context file :
<jee:jndi-lookup id="myDataSource" jndi-name="jdbc/mydb"
resource-ref="true" expected-type="javax.sql.DataSource" />
I can use a profile to determine whether or not to use this datasource, what is the alternative when using an earlier version of spring (earlier than Spring 3)
Update :
"myDataSource" will be injected when I run my app locally, on a prod environment the "jndi" lookup, will be used. To inject "myDataSource" using Spring 3 I can use "profiles" but what alternative can I use if not using Spring 3 ?
You could define all your environment depend beans into several files, such as :
beans-dev.xml
beans-prod.xml
Your XML config would be :
<beans>
<import resource="beans-${myapp.env}.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
In this case, myapp.env property is a JVM system property, i.e. configured with -Dmyapp.env=dev or -Dmyapp.env=prod. myapp.env cannot be setted from a property placeholder since Spring <import> are resolved before property placeholders.
You need to build out this kind of thing yourself. Typically by maintaining a number of different files for each profile that get composed together and a convention for picking the correct file at runtime. A -D System Property can help you pick which one. For example, we could have applicationContext-dev.xml and applicationContext-prod.xml, our applicationContext.xml would import applicationContext-${activeProfile}.xml, and you can set and load -DactiveProfile=dev; you can infer some of the other conventions like a context-param in the web.xml, etc. from how Spring3 profiles are designed.

Maven resource filtering - Spring application

I'm just wondering, at what point does the Maven resource filtering mechanism inject values from a profile into a target file? I'm asking because my application is using Spring, and depending on a JVM property, it will call one of my apps environment files which is in turn used to supply configuration information to spring beans as they get created.
I would like to move passwords and db type info from the environment file into the Maven Settings.xml file however I'm wondering will Spring overwrite or conflict with the way Maven resource filtering is working?
The goal is for Spring to decide what environment the application is running in and choose an environment file which will have already had the necessary values injected by Maven.
Thanks
Maven replaces placeholders within the process-resources phase. See http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
So when spring starts creating its context the values are there.
You can use the PropertyPlaceholderConfigurer to read a properties file and make them available in the spring context:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file://${config.dir}/external-config.properties</value>
</list>
</property>
</bean>
"config.dir" is in the system properties: java -Dconfig.dir=/dir/ or i think it can be a context parameter as well.
within the spring context ${key} from the properties file can be used to configure beans. Depending on the version of spring also annotations are available. Or there is a namespace for the PropertyResolver too.
So maven filtering and spring work nicely together.

Dealing with two different values of a property (cloud and default) in cloudfoundry and the #Value annotation

I am in reference to Spring's #Value annotation as documented here: #Value and Spring profiles.
I need to be able to have different values for a given property such as:
websiteContext=http://localhost:8080/kadjoukor
...according to whether the app is running locally or on the cloud. I am not sure how to achieve that with the #Value("${websiteContext}") annotation...
What is the best practice for dealing with such an issue?
If you are using Spring 3.1 or later, you can take advantage of bean profiles and the CloudFoundry "cloud" profile to load a different properties file depending on the environment. That might look something like this in a Spring XML configuration file:
<beans profile="default">
<context:property-placeholder location="default.properties"/>
</beans>
<beans profile="cloud">
<context:property-placeholder location="cloud.properties"/>
</beans>
Here are a few good blog posts that explain how this works in more detail:
SPRING 3.1 M1: UNIFIED PROPERTY MANAGEMENT
USING CLOUD FOUNDRY SERVICES WITH SPRING: PART 4 – SPRING PROFILES

Combine OSGi blueprint and spring configuration

Are there any good/best practices regarding the combination of Spring configuration and OSGi Blueprint (e.g. Gemini Blueprint)? Which XML files do you use? Where do you put them in your OSGi bundles (META-INF/spring, OSGi-INF)? Which of these practices will allow you to reuse your bundles in combination with a non-Gemini-implementation of Blueprint?
Background: We are in the process of switching from Spring/Spring DM to Spring/Blueprint. I am aware of Blueprint defining a <bean> element. However we occasionally face the situation that the limited bean definition capabilities of the Blueprint specification do not meet all our needs. So it seems to be a good choice to use Spring configuration within our bundles and Blueprint for wiring bundles via OSGi services.
Which XML files do you use? Where do you put them in your OSGi bundles
(META-INF/spring, OSGi-INF)? Which of these practices will allow you
to reuse your bundles in combination with a non-Gemini-implementation
of Blueprint?
Gemini Blueprint treats both of these directories equally, but OSGI-INF/blueprint/*.xml is the only one specified in the generic OSGi Blueprint specification.
A suggested practice from the Gemini Blueprint documentation is:
[...] A
suggested practice is to split the application context configuration
into at least two files, named by convention modulename-context.xml
and modulename-osgi-context.xml. The modulename-context.xml file
contains regular bean definitions independent of any knowledge of
OSGi. The modulename-osgi-context.xml file contains the bean
definitions for importing and exporting OSGi services. It may (but is
not required to) use the Gemini Blueprint OSGi schema as the top-level
namespace instead of the Spring 'beans' namespace.
I tried this, and it works great. I use Gemini Blueprint for one of my projects which has the files META-INF/spring/context.xml, which defines my beans and their relationships, and META-INF/spring/osgi-context.xml, which defines which beans to expose as/import from OSGi services and how. context.xml looks like
<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">
<bean id="myOrdinarySpringBean" class="com.acme.impl.Foo"/>
</beans>
and is a regular ordinary Spring application context with no Blueprint/OSGi configuration at all. osgi-context.xml looks like
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<service id="myOsgiService" ref="myOrdinarySpringBean" interface="com.acme.Foo"/>
</blueprint>
You could, of course, use the <beans> namespace and root element here as well, but you'd have to define a xmlns:osgi and prefix the service like so: <osgi:service .../> for that to work. In my case I don't need the Gemini specific Blueprint stuff, so I'm happy with this generic Blueprint configuration. Likewise, I could use the <blueprint> namespace in context.xml as well, but this particular application is an old one being ported to OSGi, so I prefer to keep that configuration Spring specific for now.
Another application in turn has its own osgi-context.xml like
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<reference id="myOrdinarySpringBeanImportedFromOsgi" interface="com.acme.Foo" availability="mandatory"/>
</blueprint>
and at this time doesn't, but could, have its own context.xml like
<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">
<bean id="myOrdinaryOtherSpringBean" class="com.acme.impl.Bar">
<property name="foo" ref="myOrdinarySpringBeanImportedFromOsgi"/>
</bean>
</beans>
and couldn't really care less whether myOrdinarySpringBeanImportedFromOsgi is imported from an OSGi service or defined as a regular ordinary Spring bean in the same application context.
These META-INF/osgi-context.xml configurations could trivially be moved to OSGI-INF/blueprint/ if I want to decouple yourself from the Gemini Blueprint implementation, but for the time being I prefer to keep the two halves in the same place to avoid making a mess of the directory structure.
Blueprint files should go under OSGI-INF/blueprint/ and are named *.xml (typically blueprint.xml). This location is per the OSGi 4.2 Blueprint spec and will work with Aries or Gemini.
Spring-DM files (as you probably know) go under META-INF/spring/ and are also named *.xml (typically beans.xml)
Both files should be able to peacefully co-exist. They'll only work, though, if you have support for each container installed.
Wiring should be done via the OSGi Service Registry.
As for migration, we have stayed on Spring-DM for capabilities that we couldn't do in Blueprint. Everything else has been migrated to Blueprint.

<context:load-time-weaver/> dynamically

I am looking for a way to enable aspectJ load time weaving dynamically, say based on whether a JNDI property is true.
Basically, (context:load-time-weaver) have this tag conditionally.
Any quick way to do this?
Have a look at Spring profiles:
<beans profile="production">
<context:load-time-weaver />
</beans>
If the profile name is production, LTW will be enabled. Otherwise the whole inner block is ignored. I am not sure if profile can be set using JNDI variable, but there are multiple other approaches, e.g.: JVM property, environment variable, web context parameter or you can set them programmatically.

Resources