Sunday, March 21, 2010

Fancy or ugly Spring wiring? po-TAY-to, po-TAH-to...

One situation we have run across at work is the need to be able to, at configuration, time, choose between two alternate ways to construct an object, depending on the runtime configuration. In a lot of cases, this sort of thing winds up being a datasource configured within the container, meaning that you can use JNDI to your advantage, but this case wasn't really amenable to that.

So once you've split your application context into three pieces (the main piece and each alternative piece), then what?

Spring presently doesn't have any sort of conditionals for application contexts. It does have an <import> statement. You can use property placeholder syntax to conditionalize the import, thusly:

<import resource="${whichOne}ChoiceContext.xml"/>

And that works, as long as the whichOne property is a system property. But what if you're using PropertyPlaceholderConfigurer to get placeholder material from a property file? That won't work on <import> tags, because imports take place before bean creation, which is where the configurer gets loaded.

The workaround for that, it turns out, is to rephrase your <import> like this:

<bean id="myChoiceBeanFactory" class="">
<constructor-arg type="java.lang.String" value="${whichOne}ChoiceContext.xml"/>
<bean factory-bean="myChoiceBeanFactory" factory-method="getBean">
<constructor-arg value="myChoiceBean"/>

That is, create a ClassPathXmlApplicatioContext object out of the correct context file, then call getBean("myChoiceBean") on it, and cache the resulting bean in this context as "myChoiceBean".

No comments: