Bean factory post processors [message #725378] |
Wed, 14 September 2011 11:56  |
Eclipse User |
|
|
|
Hi,
well, after extensive googling, I thought I'd ask here. So, the subject contains the key to the question, and the question is simple: are Spring's standard bean factory post processors supposed to work?
I'm asking because implementing a BeanDefinitionRegistryPostProcessor interface,
both callbacks (postProcessBeanFactory and postProcessBeanDefinitionRegistry) are
NOT called even though the constructor of the class itself is.
I found there exists the OsgiBeanFactoryPostProcessor in SpringDM - is maybe that the right way to use post processing functionality?
And a related question - I'm actually using post processors to define beans that are configured externally. The idea is to have one bundle exposing multiple services, with those services being enabled by external configuration settings. The context elements (beans and OSGi imports/exports) for each service are defined in separate context config files. The only bean automatically started is a post processor that reads the external configuration, loads (into XmlBeanFactory) the context config file for each of the services it needs enabled. Can you see any problems with this approach? Are bean definitions (including OSGi imports/exports) going to be interpreted correctly when copied to bundle's application context (since they are loaded programatically by XmlBeanFactory)?
Thanks in advance!
Tin
|
|
|
|
Re: Bean factory post processors [message #725529 is a reply to message #725520] |
Thu, 15 September 2011 01:59   |
Eclipse User |
|
|
|
Nothing easier 
It's just one bundle, attached to this post (it's an Eclipse STS project, but the bundle itself you can find in the target/ subdirectory).
So the aim is, as described in the first post, to be able to initialize only the selected services out of all the services that the bundle can provide. The logic for that is implemented in the test.bfpp.ServiceActivatingPostProcessor class. Each of the services has its own context file which the aforementioned class then loads and copies their bean definitions into current registry.
I actually lied in my first post - the bean factory post processor hook does get called, but the registry hook does not, and I want that one so that beans are defined early enough to be able to benefit from property placeholder post processing.
I'm testing this on Virgo 2.1, but with Spring updated to 3.0.5, so the registry hook should work (it was added in 3.0.1).
Thanks in advance, and any suggestions about a different approach to achieve the same goal described above are much appreciated!
|
|
|
|
Re: Bean factory post processors [message #725787 is a reply to message #725706] |
Thu, 15 September 2011 15:00   |
Eclipse User |
|
|
|
Thanks Dmitry!
Well, I read up on ManagedServiceFactory and it does look like it's designed with use cases in mind that are similar to mine. The thing is - Spring just makes it that bit more elegant to do using post processors, so it's worth pursuing doing it the "Spring way".
Is there a need to raise an issue/wish item in Virgo tracker to implement support for registry post processor, or is this already planned, or maybe can't be done because of Spring dependency (not sure how Spring framework usage is regulated between Eclipse and SpringSouce/VMWare).
And a related question - when you move the code in my example post processor class to the postProcessBeanFactory method (which does get called), a problem surfaces with Xerces apparently not being able to parse the "osgi" XML elements. It pauses for a while when starting the bean, as if it wanted to load namespace schemas from the net (i.e. from the HTTP URL defined in schema location), and then it dies with an error about not being able to find the "osgi:service" definition. Any ideas why that is - it seems like the XmlBeanFactory (the same happens if I only use XmlBeanDefinitionReader) object created in that method does not have access to the namespace schemas included with Spring bundles, but rather tries to load them directly from their URL locations?
[Updated on: Thu, 15 September 2011 15:02] by Moderator
|
|
|
|
|
|
|
Re: Bean factory post processors [message #726659 is a reply to message #726043] |
Mon, 19 September 2011 03:44   |
Eclipse User |
|
|
|
It was an interesting read, thanks, although I'm not sure who won in that comments exchange It's good to know, even though SpringSource's focus shifted away from OSGi, there is a wider group of people still working on getting it ready for more complex uses.
Meanwhile, I discovered a way to programatically add bean and OSGi service definitions with current level of post processor support, and while it might not be optimal it does work:
1. Implement a BeanFactoryPostProcessor and a BundleContextAware in the same class
2. In the postProcessBeanFactory method do this:
a) create a new OsgiBundleXmlApplicationContext
b) call setBundleContext on the object from a)
c) call setConfigLocations on the object from a), with location of the XML file(s) describing beans and services you want to instance
d) call refresh on the object from a)
e) access getBeanFactory on the object from a) to get all bean definitions and use registerBeanDefinition to register it in the current bean factory
There might be a simpler way to do it that maybe doesn't require creating a whole application context, but at least this is a good start...
[Updated on: Mon, 19 September 2011 03:45] by Moderator
|
|
|
|
|
|
|
Re: Bean factory post processors [message #900533 is a reply to message #900521] |
Tue, 07 August 2012 08:22  |
Eclipse User |
|
|
|
I'd say this is because no propertyplaceholderconfigurers are instanced and applied when you just read bean definitions. Here's a complete method that works for me, with some comments included (note that sample-setup.xml can and should contain property placeholder configurer declaration for your case to work):
@Override
public void setBundleContext ( BundleContext bc )
{
this.bc = bc;
}
@Override
public void postProcessBeanFactory ( ConfigurableListableBeanFactory factory )
throws BeansException
{
DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) factory;
// Setup the "donor" application context that will be used to load necessary
// bean definitions
OsgiBundleXmlApplicationContext ctx = new OsgiBundleXmlApplicationContext ( );
// bc obtained above - by implementing BundleContextAware.setBundleContext
ctx.setBundleContext ( bc );
// Initialize bean definition locations in the "donor" context
ctx.setConfigLocations ( new String [ ] { "META-INF/sample-setup.xml" } );
// Load bean definitions
ctx.refresh ( );
// Copy bean definitions from "donor" to current context
for ( String bean : ctx.getBeanFactory ( ).getBeanDefinitionNames ( ) )
{
// Register bean definitions in current application context
dlbf.registerBeanDefinition ( bean, ctx.getBeanFactory ( ).getBeanDefinition ( bean ) );
}
}
So, your sample-setup.xml could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
<context:property-placeholder location="file:/etc/sample.conf"/>
<bean id="someString" class="java.lang.String" factory-method="valueOf">
<constructor-arg value="${sample.value}"/>
</bean>
</beans>
|
|
|
Powered by
FUDForum. Page generated in 0.09226 seconds