A PropertyPlaceholderConfigurer is a well known tool in the Spring arena. It allows to externalize usually the most changing values of a given configuration to Java Properties files. In fact, Spring offers out-of-the-box implementations that can resolve property values from files, system properties, env properties or even web.xml context params. In addition, it's easy to create extensions to retrieve values from JNDI or database. For example, use the JNDITemplate to access the context and lookup properties:
public String resolveProperty(String property) {
String value = null;
try {
value = (String) jndi.lookup("java:comp/env/" + property);
} catch(Exception e) {
try {
value = (String) jndi.lookup(property);
} catch(Exception ex) {}
}
return value;
}
String value = null;
try {
value = (String) jndi.lookup("java:comp/env/" + property);
} catch(Exception e) {
try {
value = (String) jndi.lookup(property);
} catch(Exception ex) {}
}
return value;
}
The thing is once you have built your uber resolver chances are it will be used across all the different contexts. Unfortunately, even though the bean is inherited, BeanFactoryPostProcessors (and the PPC is one) are tightly coupled to the context where they're defined and won't do their magic in the outside world.
As a little side note, a bean factory postprocessor is a special kind of bean defined in an application context that is initialized and executed before any other bean. They can influence the behavior of the context loading. In our case it's modifying the declarations changing ${...} by an actual value. Of course, they're by definition closely coupled to Spring's life cycle.
So in Spring not being able to inherit PropertyPlaceholderConfigurers is considered a feature and it's by design. If you share a different vision and, for example, would like to share the same resolver between the contexts loaded by the ContextloaderListener and the DispatcherServlet, the good news is it can be done. We have to thank you Spring's configurability and the number of extension point it provides.
We will need two of them, the first is offered by DispatcherServlet and the second by ConfigurableListableBeanFactory. the servlet allow us (extending the class) to override the
As a little side note, a bean factory postprocessor is a special kind of bean defined in an application context that is initialized and executed before any other bean. They can influence the behavior of the context loading. In our case it's modifying the declarations changing ${...} by an actual value. Of course, they're by definition closely coupled to Spring's life cycle.
So in Spring not being able to inherit PropertyPlaceholderConfigurers is considered a feature and it's by design. If you share a different vision and, for example, would like to share the same resolver between the contexts loaded by the ContextloaderListener and the DispatcherServlet, the good news is it can be done. We have to thank you Spring's configurability and the number of extension point it provides.
We will need two of them, the first is offered by DispatcherServlet and the second by ConfigurableListableBeanFactory. the servlet allow us (extending the class) to override the
void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac);
method. This gives us a handler executed before the context is loaded (refreshed) for the first time. And it also gives us a reference to the context itself. In this situation we could add a new bean to this context easily but, better yet, we have a method to add a bean factory post-processor directly. The code is trivial, just get the previously defined bean from the (parent) context and add it. I'm using an anonymous inner class but it's not mandatory really.
wac.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
public void postProcessBeanFactory(...beanFactory) throws ... {
BeanFactoryPostProcessor resolver = beanFactory.getBean("resolver");
resolver.postProcessBeanFactory(beanFactory);
}
});
public void postProcessBeanFactory(...beanFactory) throws ... {
BeanFactoryPostProcessor resolver = beanFactory.getBean("resolver");
resolver.postProcessBeanFactory(beanFactory);
}
});
Basically that's all, change the web.xml (to point to the new class), remove the now redundant beans in the configuration files and redeploy.

0 comentarios:
Publicar un comentario en la entrada