How to dynamically add externally defined beans definitions to Spring context? - java

I have a requirement where Spring bean definitions need to be loaded dynamically from an "external" source. This external source could be some type of file, database, or web service.
I've read up on BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor classes that can do this type of thing, but I'm running into one big challenge:
The object that retrieves the bean definiton info from the external source is configured as a bean itself (e.g. DatabaseBeanDefinitionProvider) so it would need to be configured with all dependencies (e.g. DataSource) and available from the context to fetch the data.
I'm not sure where/when in the Spring application context lifecycle to do this: essentially use "existing beans to add new beans" to the context.
Any ideas experts?

The possibility to use a database table for loading persisted bean definitions is already implemented in Spring with the JdbcBeanDefinitionReader. I mentioned this just to be sure you do not reinvent the wheel ;). You can also use the PropertiesBeanDefinitionReader if you want to rely just on a bunch of properties from a plain file.
Both classes have the BeanDefinitionRegistry as dependency, the bucket, where all bean definitions will be collected during the bean definition load phase. Implementing the BeanDefinitionRegistryPostProcessor (BDRPP) interface provides this in a very convenient way.
Now, how to get it running:
Basically, if you stick to the DataSource-bound way, I would recommend to setup those dependencies by hand, means instantiating the BDRPP and dependencies in an own ApplicationContextInitializer implementation. In there you can then call applicationContext.addBeanFactoryPostProcessor(yourBdrpp) and load whatever properties you need for the DataSource under the JdbcBeanDefinitionReader.
XML will also work fine if all your dependencies are independent of any autowiring or properties replacement. You need to define them explicitly, e.g.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean class="net.bensteinert.MyBeanDefinitionRegistryPostProcessor">
<constructor-arg ref="jdbcTemplate"/>
</bean>
Only problem is, that your dataSource will have no access to any property placeholder infrastructure, That is the reason why I would tend to the programmatic solution.
Means in general, no worries about using beans for creating beans. They just need to be independent. By the way, the powerful Java Config bootstrapping is also a BeanDefinitionRegistryPostProcessor.
More details on dynamic bean definition can also be found here: How to create dynamic bean definitions in Spring
A very good introduction into the Spring Bean Lifecycle can be found here: SpringONE 2013 Presentation by Mark Secrist
Hope that helps,
so long.

Related

Bean and Dependency Injection configuration from Database Instead XML

Currently we have all service class configuration defined in Application-Context.xml file. Application context will be initialized during the application startup with all beans defined in the context file and spring handles dependency injection.
I am looking for a solution where it has to load particular service class during run time based on specific parameter from Database.
For example, there are two classes exist in code base such as FooService1.java and FooService2.java. Each class will have dependency with appropriate DAO class such as FooDAO1.java and FooDAO2.java.
Instead of defining these in applciation-context.xml file, a run time parameter will decide which service needs to be loaded and its corresponding DAO which needs to be injected. Basically what i am trying to achieve here is DB oriented Dependency Injection to keep all application context information in database instead of XML.
Tables would look like: SERVICE_BEANS, DAO_BEANS and some intermediate table to have dependency information.
I just saw JdbcBeanDefinitionReader class in spring. Can I use this to implement DB oriented DI? I don't see much example on this. Please let me know if anyone has any examples.
I think you can generate beans # runtime and register them to spring-context.
Refer to Registering beans(prototype) at runtime in Spring
Hope that helps !

How to set priority of using class

I am creating web service. I have application tier and web tier. Both of this tier using jaxb to generate object factory from xsd. Generating class are in package: my.package.v1
Now I have another project which has dependency on these project.
In context I have specify object factory:
<bean id="objectFactory" class="my.package.v1.ObjectFactory" />
when I compile and deploy application everything is OK. But there is two Object factory and he can use just one of them. Which one application use and how I change it and use another one ?
UPDATE:
Is there options how to set in spring context which class to use ?
I want change this to set right class when I have two ObjectFactory
<bean id="objectFactory" class="my.package.v1.ObjectFactory" />
There can be conflicting results and depends on Contextual classloader. I would suggest to have them in separate packages to avoid namespace conflicts
Which one of the two implementations of my.package.v1.ObjectFactory that is actually used depends on the ClassLoader.
See this question for info on how ClassLoaders resolve this kind of issue.

Spring per-environment configuration where PropertyPlaceholder is not enough

I am configuring my spring application per-environemnt and I came to following problem:
As long as the environment changes just bean constructor/properties values I am fine with using PropertyPlaceholderConfigurer.
Now I am facing the fact that the bean structure itself change in different environemnts. E.g. in test environemnt I define single bean where in production environment I define another bean of same interface which requires property of type List set - in another words different structure where PropertyPlaceholderConfigurer can't really help.
I went with defining per-environment spring xml configuration importing it via <import resource="myDefinition-${Environment}.xml />. This is also fine until I want have it optional. The resource I am defining there is #Autowired(required = false) to another bean.
Since <import ... /> doesn't allow optional attribute (as can be seen here: https://jira.springsource.org/browse/SPR-1624) I ended up having empty .xml configuration files for environemnts where I don't require having that bean. This is somewhat inconvenient.
Could anyone advice on best practice in such scenario?
Thanks.
Bean definition profiles, introduced in Spring 3.1 are designed to solve just this kind of problem. See http://static.springsource.org/spring/docs/3.1.0.RC2/spring-framework-reference/html/new-in-3.1.html

How do you make a multi-module spring configuration?

I have a multi-module (maven) spring build. All the modules publish some beans, and most also consume beans defined further down the dependency graph. Although most of it is annotation declared beans, almost every module also has one or two xml-declared beans.
Although we have a half-decent solution, but I am really wondering what is the correct/optimal way to organize the xml files in this scenario? Do you use import between the modules or is there some other way ? Do you put all the xml files in one place or spread them around according to the dependency graph? How does your solution handle partial spring contexts (typical integration tests) ?
I'd also like to have this organized in a way that lets me leverage my IDE's spring support optimally (IDEA and a few eclipse users).
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:
<plugin: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 Spring Plugin and published under Apache 2 licence. See http://github.com/SpringSource/spring-plugin for more info. There's also a more advanced sample project at Github, that shows how this works and improves modularity at GitHub. The app is sample code for my "Whoops! Where did my architecture go?" presentation which you can see the slides here or watch a recording here.
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 {
// ...
}
We simply create the application context from multiple XML config files based on usage.
For example, for testing without a server, the context is created by using all the config files in each service module.
When deployed, we access the services via Spring Remoting, and thus the client uses an application context that is initialized via an XML config which defines the proxy beans that enable remoting. Meanwhile the services are confgured by the same XML files as used by the test cases, but the application context is now loaded by either the DispatcherServlet or an EJB or MDB.
This setup allows us to tailor the Application Context for each scenario without having to duplicate any information in configuration files, which keeps maintenance much simpler. Also, there is no hard dependency between config files via imports, since that is handled at the layer above that actually creates the ApplicationContext.
Can't comment on the IDE support since we are not using it yet.

Does having many unused beans in a Spring Bean Context waste significant resources?

My model layer is being used by a handful of different projects and I'd like to use a single XML Spring Configuration file for the model regardless of which project is using it.
My question is: Since not all beans are used in all projects am I wasting resources to any significant amount if there not being instantiated? I'm not too sure how lazy Spring is about loading them since it's never been an issue until now.
Any ideas?
Taken from the Spring Reference Manual:
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup. Pre-instantiation means that an ApplicationContext will eagerly create and configure all of its singleton beans as part of its initialization process. Generally this is a good thing, because it means that any errors in the configuration or in the surrounding environment will be discovered immediately (as opposed to possibly hours or even days down the line).
However, there are times when this behavior is not what is wanted. If you do not want a singleton bean to be pre-instantiated when using an ApplicationContext, you can selectively control this by marking a bean definition as lazy-initialized. A lazily-initialized bean indicates to the IoC container whether or not a bean instance should be created at startup or when it is first requested.
When configuring beans via XML, this lazy loading is controlled by the 'lazy-init' attribute on the [bean element] ; for example:
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
But, unless your beans are using up resources like file locks or database connections, I wouldn't worry too much about simple memory overhead if it is easier for you to have this one configuration for multiple (but different) profiles.
In addition to the other comments: it's also possible to specify a whole configuration file to be lazily initialized, by using the 'default-lazy-init' attribute on the <beans/> element; for example:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
This is much easier than adding the lazy-init attribute to every bean, if you have a lot of them.
By default Spring beans are singletons and are instantiated when the application context is created (at startup). So assuming you haven't overridden the default behaviour, then a single instance of every bean will be created.
Depends upon the objects.
But, unused code is 'cruft' and will increase the cost of maintenance.
Better to delete the refs and classes. You can always restore from version control if they are needed later.

Categories

Resources