0
votes

I have a legacy Spring 3 web application which uses a configuration-database for loading config values like urls, timeouts, etc.

Currently the values from the config-db are used programmatically.

Currently there is one application context and in that the the configuration-database accessor code is initialized (a Spring Repository) along all the other components.

Because of this single context, the configuration values from the config-database can not be used in '@Value' annotations. By the time I can access the values, the context are initialised, the beans are created.

The goal would be to allow the use of config-db based values via '@Value' annotations in the beans.

So my idea was to separate the config-db accessor beans (data source, entity manager etc) into a 'mini' context and:

  1. load that mini-context at the very beginning,
  2. then load the values from the config-db into a Properties
  3. and then insert that Properties into the PropertySources of the 'real' context

I succeeded in almost everything, but I can only initialize this 'mini-context' from the classpath, not from WEB-INF (WEB-INF is not on the classpath, only WEB-INF/classes are). My current initialization looks like this:

Registration of context listener for Spring dispatcher servlet:

<servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextInitializerClasses</param-name>
        <param-value>xxx.xxx.ContextInitializer</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Then in the ContextInitializer:

public void initialize(ConfigurableApplicationContext applicationContext) {
    ClassPathXmlApplicationContext miniContext = 
            new ClassPathXmlApplicationContext("jpa-context-for-config-db.xml");
    ParameterDao parameterDao = miniContext.getBean(ParameterDao.class);
    Properties propertiesFromConfigDb = getPropertiesFromConfigDb(parameterDao);
    applicationContext.getEnvironment().getPropertySources().addFirst(
            new PropertiesPropertySource("parameterDaoBasedProperties", propertiesFromConfigDb));
    miniContext.close();
}

This is working, but

  1. I have to put the mini-context xml into /WEB-INF/classes which is not where other context files are (other context files are in /WEB-INF)

  2. I can't use property-placeholders or util:properties in the mini-context with 'location="/WEB-INF/...."'.

I tried to use GenericXmlApplicationContext and played with it's setResourceLoader but haven't succeeded yet.

So is there a way to load a spring context.xml programmatically from WEB-INF and not from the classpath?

1

1 Answers

0
votes

In a spring web application the content of WEB-INF can be accessed via org.springframework.web.context.support.ServletContextResourceLoader . That class can load resources from WEB-INF.

So the initialize method should look like this:

public void initialize(ConfigurableApplicationContext applicationContext) {
    ServletContext servletContext = ContextLoaderListener.getCurrentWebApplicationContext().getServletContext();
    GenericXmlApplicationContext miniContext = new GenericXmlApplicationContext();
    miniContext.setResourceLoader(new ServletContextResourceLoader(servletContext));
    miniContext.load("/WEB-INF/jpa-context-for-config-db.xml");
    miniContext.refresh();
    ParameterDao parameterDao = miniContext.getBean(ParameterDao.class);
    Properties propertiesFromConfigDb = getPropertiesFromConfigDb(parameterDao);
    applicationContext.getEnvironment().getPropertySources().addFirst(
            new PropertiesPropertySource("parameterDaoBasedProperties", propertiesFromConfigDb));
    miniContext.close();
}