Spring Java Configuration in Servlet 3.x containers

As stated on the SpringSource site

Spring is the most popular application development framework for enterprise Java™. Millions of developers use Spring to create high performing, easily testable, reusable code without any lock-in.

We are going to take a look at getting Spring+Spring MVC setup in a servlet 3.x container such as Tomcat, WebSphere, Jboss or any of the many other JavaEE/Servlet servers.

Maven Dependencies

First thing we need to do is add Maven dependencies to our pom files.  We’ll be using a multi-module project as described in an earlier post.  We’ll have three pom files, one parent, one core, and one webapp.  In our Parent POM add the following artifacts to the dependencyManagement section


<dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>javax.servlet-api</artifactId>
 <version>${servlet.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>jstl</artifactId>
 <version>${jstl.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>javax.servlet.jsp</groupId>
 <artifactId>javax.servlet.jsp-api</artifactId>
 <version>${jsp.version}</version>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>javax.el</groupId>
 <artifactId>javax.el-api</artifactId>
 <version>${el.version}</version>
 <scope>provided</scope>
 </dependency></pre>
<!-- Web application development utilities applicable to both Servlet
 and Portlet Environments (depends on spring-core, spring-beans, spring-context)
 Define this if you use Spring MVC, or wish to use Struts, JSF, or another
 web framework with Spring (org.springframework.web.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-web</artifactId>
 <version>${org.springframework.version}</version>
 </dependency>

<!-- Spring MVC for Servlet Environments (depends on spring-core, spring-beans,
 spring-context, spring-web) Define this if you use Spring MVC with a Servlet
 Container such as Apache Tomcat (org.springframework.web.servlet.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 <version>${org.springframework.version}</version>
 </dependency>

<!-- Application Context (depends on spring-core, spring-expression, spring-aop,
 spring-beans) This is the central artifact for Spring's Dependency Injection
 Container and is generally always defined -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>${org.springframework.version}</version>
 <exclusions>
 <exclusion>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 </exclusion>
 </exclusions>
 </dependency>

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>${org.springframework.version}</version>
 <exclusions>
 <exclusion>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 </exclusion>
 </exclusions>
 </dependency>

<!-- Expression Language (depends on spring-core) Define this if you use
 Spring Expression APIs (org.springframework.expression.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-expression</artifactId>
 <version>${org.springframework.version}</version>
 </dependency>

<!-- Bean Factory and JavaBeans utilities (depends on spring-core) Define
 this if you use Spring Bean APIs (org.springframework.beans.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>${org.springframework.version}</version>
 </dependency>

Note the provided scope on the servlet dependencies.  This means we are expecting our servlet container to already have these dependencies available to our application so we don’t need to package them up, but still need them for compiling.  The default scope for our other artifacts is compile which means they’ll be used to compiled and packaged up with our project

Also we are excluding commons-logging from spring core in favor of a slf4j implementation.

Next in the Parent POM add our versions under the properties section.  The servlet version should correspond to what your container provides and the spring dependencies should be the newest stable version that works with your servlet version.  These should work for 3.0.x containers.


<el.version>2.2.4</el.version>
 <jsp.version>2.2.1</jsp.version>
 <jstl.version>1.2</jstl.version>
 <org.springframework.version>3.2.4.RELEASE</org.springframework.version>
 <servlet.version>3.0.1</servlet.version>

Now we need to add the actual depenencies to our project modules for use.

<dependencies>
<dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>javax.servlet-api</artifactId>
 </dependency>
 <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>jstl</artifactId>
 </dependency>
 <dependency>
 <groupId>javax.servlet.jsp</groupId>
 <artifactId>javax.servlet.jsp-api</artifactId>
 </dependency>
 <dependency>
 <groupId>javax.el</groupId>
 <artifactId>javax.el-api</artifactId>
 </dependency>
 <!-- Web application development utilities applicable to both Servlet and
 Portlet Environments (depends on spring-core, spring-beans, spring-context)
 Define this if you use Spring MVC, or wish to use Struts, JSF, or another
 web framework with Spring (org.springframework.web.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-web</artifactId>
 </dependency>

<!-- Spring MVC for Servlet Environments (depends on spring-core, spring-beans,
 spring-context, spring-web) Define this if you use Spring MVC with a Servlet
 Container such as Apache Tomcat (org.springframework.web.servlet.*) -->
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 </dependency>
 <dependency>
 <groupId>${project.groupId}</groupId>
 <artifactId>core</artifactId>
 </dependency>
 </dependencies>

Adding this to the webapp pom give’s us our servlet and spring web/mvc dependencies as well as our core project module if you didn’t already add it.

 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 </dependency>

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 </dependency>

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-expression</artifactId>
 </dependency>

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 </dependency>

These pull the rest of the Spring dependencies into our core project which then get pull transtively to our webapp project.

Configuration

We are going to save why we use Spring, and other IoC containers for Java applications, for a later post and jump right into some configuration code.  Containers that implement the Java EE Servlet Spec 3.x enable us to skip the standard /WEB-INF/web.xml file in favor of simpler java class where we can pragmatically configure servlets.  So lets delete the web.xml file generated by our maven webapp archetype (keep the /WEB-INF/ folder) and look at how we use Java to register our servlets.

First just to stay, all the Spring documentation is very well written and complete. Looking at http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/new-in-3.1.html#new-in-3.1-servlet-3-code-config we see a reference to WebApplicationInitializer where I’ve slightly modified the code under the A 100% code-based approach to configuration


public class ServletConfig implements WebApplicationInitializer {

@Override
 public void onStartup(ServletContext servletContext)
 throws ServletException {

// Create the 'root' Spring application context and register our
 // MvcConfig spring class
 AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
 rootContext.register(MvcConfig.class);

// Manage the lifecycle of the root application context
 servletContext.addListener(new ContextLoaderListener(rootContext));

// Create the dispatcher servlet's Spring application context
 AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();

// Register and map the dispatcher servlet
 ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
 "dispatcher", new DispatcherServlet(dispatcherContext));
 dispatcher.setLoadOnStartup(1);
 dispatcher.addMapping("/");
 }

}

You can create this class anywhere in your project and your servlet 3 container will pick it up and execute the code when you start up your application.  I’ve gone with root.package.path.config for all my servlet and spring configuration classes that aren’t specific to application business functionality.

How is Spring doing this with Servlet 3?

So this new configuration method is built on top of Servlet 3 dependency, so let’s take a quick look on how spring is achieving this auto detection and configuration.  First looks take a look at the SpringServletContainerInitializer class.  Here we see the class definition as


@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer

If you look at the Javadoc for ServletContainerInitializer you can see it says that there must be a file under META-INF/services which declares all implementations of the interface.  If we look at spring-web/META-INF/service/javax.servlet.ServletContainerInitializer file we see one entry org.springframework.web.SpringServletContainerInitializer

Now we know how spring registers it’s SpringServletContainerInitializer with the container let’s take a look at how it picks up our WebApplicationInitializer implementations.  You’ll notice @HandlesTypes(WebApplicationInitializer.class) annotation on SpringServletContainerInitializer.  This annotation tells the container to scan for all classes implementing that interface and pass them in as the first parameter in the method


public interface ServletContainerInitializer {

 public void onStartup(Set<Class<?>> c, ServletContext ctx)
 throws ServletException;
}

Which will then pass in all your WebApplicationInitializer implementations for Spring to invoke and handle the onStartup methods.

Finally Our Servlet Configuration

Now that we know how our container is loading our servlet information lets go back to our original configuration and take a look at the Spring classes we are registering.

We need to configure two things, Springs implementation of ServletContextListener which allows Spring to startup and shutdown with our application.  The second thing we need to register is Spring’s DispatcherServlet which will let us use Spring MVC which we’ll discuss more later.

Listener


// Create the 'root' Spring application context and register our
 // MvcConfig spring class
 AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
 rootContext.register(MvcConfig.class);

// Manage the lifecycle of the root application context
 servletContext.addListener(new ContextLoaderListener(rootContext));

Serlvet


// Create the dispatcher servlet's Spring application context
 AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();

// Register and map the dispatcher servlet
 ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
 "dispatcher", new DispatcherServlet(dispatcherContext));
 dispatcher.setLoadOnStartup(1);
 dispatcher.addMapping("/");

As you may have notice we configure multiple AnnotationConfigWebApplicationContext, one for the listener and another for the servlet.  Springs AnnotationConfigWebApplicationContext is hierarchical so the root context belongs to the listener, and then the context for the servlet can override beans from the root context for that servlet. Since we are keeping our application very simple and will have no need for this functionality we only register our Spring @Configuration class MvcConfig.class in the root context.

In our DispatcherServlet we overrider the default servlet ‘/’ mapping so that Spring MVC can handle all our incoming request, note that this is different than mapping ‘/*’ which will cause problems later when using Spring MVC.

Let’s take a quick peak at our MvcConfig.class just to see how Spring is taking over at this point.


@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.company.artifact")
// do a full scan of the root package to pickup annotationed classes
public class MvcConfig extends WebMvcConfigurerAdapter

The @Configuration annotation tells Spring that this is a configuration class (like the old .xml application context files).  For the  @ComponentScan annotation we pass in our root package name so that Spring will automatically scan and pickup any other annotated classes, including other @Configuration classes and beans.

That’s it

Now with very little code we have Spring hooked into our web application.