Friday, September 16, 2011

Spring Application Context Configuration

I have been working with spring framework for a long time and early on I used to maintain different context files for testing, I have done that mostly because of the location of context file was /WEB-INF/ and it is not in either Eclipse or Maven compile/run time class path and my tests would barf with a dreaded File Not Found exception. I realized a better location for spring config files that does not involve MVC configuration should be a source folder under java run time. Since I use Maven project structure It dawned on me that I could use src/main/resources that would resolve compile/run time issues for Eclipse, Maven and also the Server.

Location of spring context files
This is the typical configuration in most my java enterprise applications, I use maven project directory structure so the logically the context files go into resource directory. I also dabbled into placing my spring config files src/test/resources but It still required me to maintain two sets of config files. So I finally settled on src/main/resources as my config directory.
  • src/main/resources/spring-config (Service layer)
  • src/main/webapp/WEB-INF/myapp-servelt.xml (I tend to keep MVC config like controller and view resolver under WEB-INF)
Spring Context files
I used to have more context files but since advent of annotations that number is drastically reduced. You can see that I am firmly in the annotation camp when it comes to configuration whether it is spring or hibernate.  I have typically used the following configuration
Context Files Merging
If you would prefer to minimize the number context file in your application during deployment, You can do some thing like this create an applicationContext.xml and import all the context files that are not part of MVC config. I think it is a good idea to keep MVC config separate. I have listing of an example context file with resources being imported


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


<context:component-scan base-package="prasanna" />
<import resource="classpath:datasource.xml"/>
<import resource="classpath:applicationContextDAO.xml"/>

</beans>


Junit Testing
It makes running tests easy no need to worry about context file being not found. You can create base test that could be extended by all the other tests some thing like this.

@ContextConfiguration(locations={"classpath:spring-config/applicationContext.xml"})
public class BaseSpringConfigTest
{

}

Since spring context files are under resources directory we can always be sure that Junit tests will run with out fail

Context File for Deploying
Now let's look at the point on how do we deploy the context files to a web application. If you look at any of the spring examples you would see that context files are always under /WEB-INF. In this case every thing still remains the same, I just use the ubiquitous classpath suffix to load the context file. Look at the listing for dispatch servlet below in web.xml


<servlet>
<servlet-name>Spring Dispatch Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-config/applicationContext.xml
 /WEB-INF/mvcConfigContext.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>


If you look at the listing, I used classpath suffix config to load applicatonContext.xml but I still have mvc config file under the WEB-INF directory. If you use Spring ContextLoaderListener you still do the same just load them as below

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config/applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


<servlet>
<servlet-name>Spring Dispatch Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
 /WEB-INF/mvcConfigContext.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>


if you do the above configuration spring as it boot straps the application context treats the context loaded by the listener as the parent of the context loaded by dispatch servlet. I don't want to get to details into it refer to spring documentation or this excellent article.

As a foot note I would say location of config files, It is more to do with being consistent as it helps with on boarding / hand offs as project resources are shifting. 



Thursday, September 15, 2011

Spring Context Configuration and Deployment

I think as an application designer/developer when you are making decisions regarding configuration, It is critically important to think about deployment. I have had my share deployment woes early on, I think that is what made me a firm believer in making deployment task to be as routine as possible to limit the developer's role to bare minimum. In one of the application I work on, We moved the application deployment configuration to data base and applied the configuration using JMX Mbeans as application starts up in a fail fast mode.

Deployment
Here are some things that I learned that would make for a smooth deployment

  • Keep the application configuration during deployment as simple as possible
  • If you don't do that, There will be a lot of hand holding in an enterprise environment where deployment tasks are handled by administrators with little knowledge of (code and application function)
  • I am firm believer in building an artifact (ear or war) using a build tool, There are plenty of build tools available Jenkins, Bamboo , Cruise Control to name a few
  • There should be one and only one deployment artifact (ear or war) that should be preferably available as a download to deployment team to deploy it on either (Quality/Performance/Production) environment
  • Only one deployment artifact means, If you property use files that differ for each environment then that needs to be taken into account during development
  • For example, We had a problem where we needed to configure a JMS Message broker, Web Service that were connected to different sources (IP Address, Channel name, Q name) in different deployment environments (dev, qa, prod etc) 

I am going in reverse with deployment as being first just to bring out the nuances in deployment. I think one of key aspect of application design/development is the configuration that fits various deployment environments (i.e dev, qa, prod). 


Application Configuration
In a typical enterprise java environment there is some kind of application specific config during deployment. I am going to keep it simple for this blog and just provide a template on how one can solve problem like these.  Let's take a look at a web application with spring integration that communicates with a JMS Message broker, It needs to communicate with Test or Prod JMS Message broker based on the deployment environment. I have listed config files that are needed to deploy this application
  • applicationContext.xml  (Core spring context file with service layer beans)
  • jmsBrokerContext.xml (Spring Integration config for JMS Q)
  • messagebroker_qa.properties (Test message broker properties)
  • messagebroker_prod.properties (Production message broker properties)
I am listing a typical Message Broker configuration, To configure this application to communicate with appropriate Message Broker we could create property files for each environment (i.e. dev, qa or prod). 
  1. mqconn.hostName=dns name of the host
  2. mqconn.port=some port
  3. mqconn.queueManager=q manager
  4. mqconn.channel=q channel
  5. mqconn.baseQueueName.qname=queue name
Once property files are created for each environment, We could then pass a environment variable as JVM argument as defined below.
  • -Dserver_env=qa  (pass JVM argument for test server)
  • -Dserver_env=prod (pass JVM argument for prod server)
Then we could use the property place holder to inject the properties for the given server environment. As the spring container boots up It will substitute (qa for ${server_env}) for qa environment and (messagebroker_prod.properties) in production environment

<context:property-placeholder location="classpath:messagebroker_${server_env}.properties"/>

<bean id="connectionFactoryMQ" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${mqconn.hostName}" />
<property name="port" value="${mqconn.port}" />
<property name="queueManager" value="${mqconn.queueManager}" />
<property name="channel" value="${mqconn.channel}" />
<property name="transportType" value="${mqconn.transportType}" />
</bean>

This is one way same deployment artifact could used to do deploy it in environment we choose, But all this starts during the application design/development itself.