Back Forum Reply New

XmlWebApplicationContext and PropertyPlaceHolderConfigurer

I am trying to make our web app load properties files containing values to be substituted into the spring xml such as the examples in the docs (substituting database properties).

I have written a ServletContextListener where in the contextInitialized(ServletContentEvent event) method I programmatically create a WebApplicationContext. I do this because at this point I can programmtically find out the environment I am running in and the location and thus create the relevant paths to the properties file for that process.

The code is:

XmlWebApplicationContext webappContext = new XmlWebApplicationContext();
webappContext.setServletContext(event.getServletCo  ntext());
webappContext.refresh();

PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setProperties(props);
cfg.postProcessBeanFactory(webappContext.getBeanFa  ctory());
this.context.setAttribute(WebApplicationContext.RO  OT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,        webappContext);
Assume props to be the properties object containing the name value pairs to be substituted into the beans.

This seems to all work fine and starts up etc. However on first getting a bean which has a substitution, the application fails as the value has not been substituted. Can anyone point me in the correct direction to substitute values - I have done this before using a basic BeanFactory without issue - but this fails for me.

NEW INFO:
Having just debugged using source code - it does look like the properties are working. The log shows

[XmlWebApplicationContext] Refreshing org..web.context.support.XmlWebAppl  icationContext@f0dcb3Then further down I get in the logs

[DispatcherServlet] FrameworkServlet 'spring-dispatcher': initialization started
[XmlWebApplicationContext] Refreshing org..web.context.support.XmlWebAppl  icationContext@ffefc9: display name [WebApplicationContext for namespace 'spring-dispatcher  -servlet']; startup date [Fri Apr 11 17:25:45 BST 2008]; parent: org..web.context.support.XmlWebAppl  icationContext@f0dcb3So it looks like a new XmlWebApplicationContext is instantiated again with the original being its parent.......now I guess the question is why does this happen.

Hi!

I also have  a similar problem.
applicationContext.xml loading normally, however I want to load a property file (extract from applicationContext.xml):   lt;bean id=quot;propertyConfigurerquot;    class=quot;myImpl.ExposablePropertyPaceholderConfigure  rquot;gt;        lt;descriptiongt;        This bean contains all configuration data.        lt;/descriptiongt;       lt;property name=quot;locationsquot;gt;lt;listgt;   lt;valuegt;web.propertieslt;/valuegt;lt;/listgt;       lt;/propertygt;   lt;/beangt;

But when tomcat starts I got the following exception:

org..beans.factory.BeanInitializati  onException: Could not load pr
operties; nested exception is java.io.FileNotFoundException: Could not open Serv
letContext resource [/web.properties]

But the file is located in the WEB-INF directory. (I've also tried it in the classes folder).
What's the problem? I've tried it in simple (no Web/no struts) application.

Thanks!

Please use the [ code][/code ] tags when posting code.

If the file is located in the WEB-INF directory then tell your class that it is there. Code:
lt;bean id=quot;propertyConfigurerquot; class=quot;myImpl.ExposablePropertyPaceholderConfigure rquot;gt;
lt;descriptiongt;
This bean contains all configuration data.
lt;/descriptiongt;
lt;property name=quot;locationsquot;gt;
lt;listgt;
lt;valuegt;WEB-INF/web.propertieslt;/valuegt;
lt;/listgt;
lt;/propertygt;
lt;/beangt;
of if it is at the root of the classpathCode:
lt;bean id=quot;propertyConfigurerquot; class=quot;myImpl.ExposablePropertyPaceholderConfigure rquot;gt;
lt;descriptiongt;
This bean contains all configuration data.
lt;/descriptiongt;
lt;property name=quot;locationsquot;gt;
lt;listgt;
lt;valuegt;classpath:web.propertieslt;/valuegt;
lt;/listgt;
lt;/propertygt;
lt;/beangt;

Originally Posted by alexkoonI have written a ServletContextListener where in the contextInitialized(ServletContentEvent event) method I programmatically create a WebApplicationContext. I do this because at this point I can programmtically find out the environment I am running in and the location and thus create the relevant paths to the properties file for that process.

Creating your own ServletListener seems like overkill for this. Originally Posted by alexkoonSo it looks like a new XmlWebApplicationContext is instantiated again with the original being its parent.......now I guess the question is why does this happen.

This happens because you end up with 2 contexts. One loaded by the ContextLoaderListener and one loaded by the DispatcherServlet. The one loaded by the CLL normally only includes the application classes (services, repositories etc.). The one loaded by the DS is the one that can use the stuff from its parent but it self defines additional beans. For a DS this normally are the classes used on the web-tier, ie. Controllers, ucl Mappings etc.

Thanks for the quick reply!
It works, and sorry for the missing code tags.


Originally Posted by Marten DeinumCreating your own ServletListener seems like overkill for this.

This happens because you end up with 2 contexts. One loaded by the ContextLoaderListener and one loaded by the DispatcherServlet. The one loaded by the CLL normally only includes the application classes (services, repositories etc.). The one loaded by the DS is the one that can use the stuff from its parent but it self defines additional beans. For a DS this normally are the classes used on the web-tier, ie. Controllers, ucl Mappings etc.

I found out from further reading that each DS has its own context. Anyway - I refactored the xml so the DS controllers are defined in its own XML. I extended the ContextLoaderListener to programmatically utilise the PropertyPlaceholderConfigurer. So I now haveCode:
super.contextInitialized(event);

XmlWebApplicationContext webappContext = (XmlWebApplicationContext) event.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setProperties(props);
cfg.postProcessBeanFactory(webappContext.getBeanFactory());
When I call super.contextInitialized(event) I can see my beans getting instantiated with the variable names and not the parameterised values - this is fine as I have not instantiated and executed the us of  a PropertyPlaceholderConfigurer. I then create the PPC and call postProcessBeanFactory. I can now see the bean definitions in the webappContext contain the relevant property values now - but the beans aren't refreshed or recreated with the new parameterised values. IF I call refresh on the webapp context again I get the beans without the PPC.

So how do I force the webappcontext bean factory to recreate the beans (most are singletons) with the parameterised names populated? I need to do this programmatically as I determine at runtime what properties to use.

default-lazy-init fixed the issue as I need to apply the PropertyPlaceHolderConfigurer to the bean definitions before any beans are instantiated.
¥
Back Forum Reply New