We use wildcarded imports in the modules to allow other modules contribute beans to the module declaring the import:
<import resource="classpath*:com/acme/**/*-core-support.xml" />
Modularity
Modules that want to contribute to the "host" just have to place a correctly named files in src/main/resources/com/acme
in this case to be picked up automagically. If you use classpath scanning (by <context:component-scan />
it will become even easier).
Another thing that helps in that regard is some small Spring extension that picks up beans of a given type and republishes them in ApplicationContext
again. By doing something like this:
<hera:list id="beanList" class="com.acme.MyCoolPluginInterface" />
<bean class="com.acme.MyPluginHost">
<property name="plugins" ref="beanList" />
</bean>
In combination with the wildcarded import this will:
- Collect all beans found in the
ApplicationContext
that implement MyCoolPluginInterface
and wrap them in a list registered as beanList
in the ApplicationContext
.
- Allow the
MyPluginHost
to reference that list.
In fact, you now can simply extend your app by adding plugin modules to the classpath (aka dependency in Maven).
That tiny Spring extension is called Hera and published under Apache 2 licence. See http://hera.synyx.org for more info.
Different environments
Usually we configure our apps to run in the target environment (using JNDI lookups and stuff). Of course you would like to use the standard PropertyPlaceholderConfigurer
mechanisms to externalize configuration that has to be touched by admins or will change through various environments.
For integration tests we usually have additional config files in src/main/test
that get loaded additionally to the normal config files overriding the critical beans that tie the configuration to the environment. E.g. if you have a datasource in your normal config file
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource" />
you would override this in your test-context.xml
by using
<bean id="dataSource" class="...DataSource" />
<!-- config -->
</bean>
and importing that after the original one in the test class
@ConfigurationContext(locations = {"app-context.xml", "test-context.xml"})
public FooBarIntegrationtest {
// ...
}
Regards,
Ollie