| Sign In/My Account | View Cart |
Advanced Configuration of the Spring MVC Framework
Pages: 1, 2, 3
The next logical idea is to try to move this host configuration to the web.xml file (if possible), since it is usually modified less often than applicationContext.xml. Luckily, there is a solution available for us to use. Take a look at the following example of the web.xml configuration snippet:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext-somehost.com.xml
</param-value>
</context-param>
As you can see, beside the usual ContextLoaderListener that is usually found in the web.xml file, we put the contextConfigLocation context parameter configuration. This parameter is used to instruct the framework where to look for these configuration files. If it is omitted, Spring will look only in the applicationContext.xml, but here we defined our host-specific configuration file to be used as well.
With this approach we moved all host-specific configuration from the applicationContext.xml file and thus eased its synchronization among various application deployments.
If this approach becomes your new habit, there is one more thing you can do to make it more flexible. By following the instructions that follow, you can remove host-specific configuration even from the web.xml file.
In order to do that, we need to create our specific application context class:
package net.nighttale.spring.util;
import java.net.InetAddress;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class PerHostXmlWebApplicationContext
extends XmlWebApplicationContext {
protected String[] getDefaultConfigLocations() {
String hostname = "localhost";
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
}
String perHostConfiguration = DEFAULT_CONFIG_LOCATION_PREFIX
+ "applicationContext-"
+ hostname
+ DEFAULT_CONFIG_LOCATION_SUFFIX
;
logger.debug(
"Adding per host configuration file: "
+ perHostConfiguration
);
if (getNamespace() != null) {
return new String[] {
DEFAULT_CONFIG_LOCATION_PREFIX
+ getNamespace()
+ DEFAULT_CONFIG_LOCATION_SUFFIX
, perHostConfiguration};
}
else {
return new String[] {
DEFAULT_CONFIG_LOCATION
, perHostConfiguration};
}
}
}
This class extends Spring's XmlWebApplicationContext, which is used by default. The XmlWebApplicationContext class takes the configuration for the web application from XML definition files. By default, it configures the application from applicationContext.xml and [servlet-name]-servlet.xml files. The only additional task that our class performs is getting the name of the host on which it is executed and adding the applicationContext-[hostname].xml file to the list of configuration files.
In order to use this class, we need to compile it, include it in the classpath, and instruct Spring framework to use it. The first two steps are well-known and we will not describe them here. We can instruct Spring to use it through the contextClass context parameter. Instead of the previous configuration in the web.xml file, we can put something like this:
<context-param>
<param-name>contextClass</param-name>
<param-value>
net.nighttale.spring.util.PerHostXmlWebApplicationContext
</param-value>
</context-param>
If this configuration snippet is used, our class will be used and three files will be used to initialize the framework: [servlet-name]-servlet.xml, applicationContext-[hostname].xml, and applicationContext.xml.
As you can see, the applicationContext.xml and web.xml files are now completely free of any specific configuration details and there is no fear that you will break your configuration during the application update.
However, there is one drawback to this approach. It is reflected in the need to have this third configuration file on the application deployment, whether you will use it or not. In the case that there is no specific host configuration needed, it could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans></beans>
Finally, you need to know what specific hostname our application context class will look for. The easiest way to check your host's name is to execute the following code on the machine:
System.out.println(InetAddress.getLocalHost().getHostName())
You can execute this as Java code or as a script in your favorite scripting language with a Java-like syntax, such as BeanShell or Groovy. When you have the name of the host, you should create a default empty /WEB-INF/applicationContext-[hostname].xml file (like the one we have defined above) and you'll be ready to go.
In this article, I've presented some configuration tips that could ease your day-to-day work with the Spring MVC framework. If you ever find yourself trying to figure out how to maintain various web application deployments, try to find the most suitable solution for your development process. It will make your life much easier.
Dejan Bosanac is a software developer, technology consultant and author. He is focused on the integration and interoperability of different technologies, especially the ones related to Java and the Web.
Return to ONJava.com.
Showing messages 1 through 11 of 11.
Refer to Spring instead of Spring MVC
Use
<bean id="servletPropertyConfigurer"
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="location"
value="classpath:path/to/fallback.properties" />
</bean>
<bean id="myService" class="nl.novumsoftware.MyService">
<property name=”url”>
<bean class=”org.springframework.jndi.JndiObjectFactoryBean”>
<property name=”jndiName”>
<value>java:comp/env/databaseUrl</value>
</property>
</bean>
</property>
</bean>
<Context path="/myweb" ... >
<Environment name="databaseUrl" type="java.lang.String" value="jdbc:oracle:thin:@myHost:1521:myInstance"/>
</Context>
This permits easy property substitution and automated editing of XML configs whilst maintaining XML-correctness and validity (e.g. character encodings, entity encoding etc.)
You can go further and insert or remove subsections of XML as you require.
It was originally designed for J2EE configurations, but it's certainly suitable for other problem domains, such as the Spring configs shown here.
Yes, you are absolutely correct - actually, I've used similar approach. These configuration files are stored in version control, but servers were able to retrieve them from one central location. Your solution will work perfectly, but the system I described has some specifics.
It seems that I forgot to mention that we have several servers that execute the same web application and the set of settings that could be configured is identical and in some cases even values of some settings could be the same amoung all (or groups) of servers.
In general, the problem with configuration could be quite a twofold - from the one side, it's necessary to support evolution of the system during the normal system lifecyle (new versions, updates etc) and, from the other side, it's necessary to solve scalability problems - say, have ability to add additional servers to farm without necessity to rebuild/redeploy other servers.
Actually, the last problem was more important for our system, since scalability and dynamic adding of new servers was just a critical requirement.
Initially we simply used properties files stored on shared file system, but as system grows, we created simple server that provides configurations to production servers - and that' s why we don't have to maintain them on deployment locations - we have to maintain only in single central place.
So far this scheme seems to be quite simple to support and maintain and works fine for us.
However, it could be quite a specific for our system and for particular project it's definitely necessary to analyze all requirements carefully to decide which approach is more suitable and should be used.
Best regards,
Andrew Sazonov
SoftAMIS
http://www.soft-amis.com
Hi Dejan!
Thank you for your great article - it's very useful and it was real pleasure for me to readit.
I'd just like to note that there could be another way to configure web application. This is approach I've used and it worked find for me.
Actually, this is combination of property placeholder and ContextLoaderListener.
The project I'm worked on included several web servers which may be added dynamically. Including all possible configuration files in war or building war file for every deployment was not acceptable option due some project' requirements.
Briefly, I've used the following scheme:
That's all - such a solution allowed me to have single .war file for arbitrary server, but have ability to convigure them individually.
If someone is interested in details, I'll be glad to provide sample code.
I hope my solution could be helpful
Best regards,
Andrew Sazonov
SoftAMIS
http://www.soft-amis.com
Additional way to configureZIP contains sources for classes I've wrote and fragment of web.xml configuration and Spring configuration
In this sample I've included only code that reads properties from file, but to illustrate general approach I suppose that particular way of obtaining them is not too important
Best regards,
Andrew Sazonov
SoftAMIS
http://www.soft-amis.com
server.jdbc.user=live_user
server.jdbc.url=jdbc:postgresql://db.host.com:5432/db
server.magic.file.location=/var/magic_file
devel.jdbc.user=devel_user
devel.jdbc.url=jdbc:postgresql://devel-db.host.com:5432/db
devel.magic.file.location=c:\\var\magic_file
my.property=some other prop
<bean id="propertyConfigurer"
class="com.util.spring.HostPrecedingPropertyPlaceholderConfigurer">
<property name="location" value="classpath:config.properties" />
</bean>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
Then append in a new "HostPrecedingPropertyPlaceholderConfigurer" class
http://jdwyah.blogspot.com/2006/06/alternatives-to-advanced-configuration.html