I'm trying to read properties from a properties file, whose filename will be different for each of our environments, like local.properties, dev.properties, etc. These properties files will only contain the connection information for their corresponding mongodb instances like host, port, and dbname. Normally this sort of thing would be done with a JNDI definition in our app server, but there are no implementations of that for Mongo currently.
Since I am using WebLogic 10.3.6, I am not able to use the Servlet 3.0 specification and therefore cannot use Java-configuration for Spring, only the XML at this time. So the approach I am trying to use is to have a contextInitializerClass context-param defined in my web.xml and then setting that to a class that implements ApplicationContextInitializer and sets the Spring active profile manually. However, at startup of WebLogic or at redeploy, neither are invoking my custom initializer class and my profile is not getting set.
My question is, does Spring's contextInitializerClass have a dependency on Servlet 3.0 or is there something else that I am missing?
Code that I have defined:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextInitializerClass</param-name>
<param-value>com.myapp.spring.SpringContextProfileInit</param-value>
</context-param>
<!-- Location of spring context config -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
...
SpringContextProfileInit.java
public class SpringContextProfileInit implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
private static final Logger log = LoggerFactory.getLogger(SpringContextProfileInit.class);
public SpringContextProfileInit() {
log.debug("Got the constructor");
}
@Override
public void initialize(ConfigurableWebApplicationContext ctx) {
ConfigurableWebEnvironment environ = ctx.getEnvironment();
log.debug("Got the environment, no profiles should be set: "+ environ.getActiveProfiles());
/*
* Here I am setting the profile with a hardcoded name. In the real app,
* I would read from a separate properties file, always named app.properties
* which would live on the app server's classpath. That app.properties file
* would contain a property directing the Spring Profile to use.
*/
environ.setActiveProfiles("local");
log.debug("Now should be set to local: "+ environ.getActiveProfiles());
ctx.refresh();
}
}
servlet-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:property-placeholder properties-ref="deployProperties" />
...
<beans profile="local">
<bean id="deployProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"
p:location="WEB-INF/local.properties" />
</beans>
<beans profile="beast, dev">
<bean id="deployProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"
p:location="WEB-INF/dev.properties" />
</beans>
</beans>
When I try to deploy the application, I get the exception:
NoSuchBeanDefinitionException:No bean named 'deployProperties' is defined
which would be expected if the profile is not set. My logs don't show that any of my debug statements are printed. I have also tried moving the contextInitializerClass parameter to be an init-param of my DispatcherServlet, but that gave the same results.
My constraints are that
I cannot set the profile from within my Maven scripts because our company uses the same artifact to push to all environments.
I also cannot change versions of WebLogic or use the newest servlet spec due to it being container dependent.
My current versions are:
- Spring 3.1.2.RELEASE
- WebLogic 10.3.6
- javax.servlet-api 2.5
Has anyone else seen this problem and knows how I can get my initializer class loaded? Or is there a better way to do what I am trying to do?
This looks related to another poster's question that has not been answered: Spring MVC 3.1 Using Profiles for environment specific Hibernate settings