Monday 25 January 2016

Replacing web.xml with Java based configuration for Servlet 3.x Webapplications using Spring

Background



As we know if you want to deploy a web app in a container like tomcat you have a context file called web.xml that creates context necessary for you app to run. For eg. you can provide libraries that will be available to your web app. 

Your typical web.xml will look like - 


<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Spring Web MVC Demo Application</display-name>

  <servlet>
      <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
     <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
  </servlet-mapping>
   

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>

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


Lets see its Java equivalent

Java Configuration

  • For Java configuration you can write your own class that implements WebApplicationInitializer  interface and override it's
    onStartup() method.
  • WebApplicationInitializer is an interface provided by Spring MVC that ensures your implementation is detected and automatically used to initialize any Servlet 3 container.
  • An abstract base class implementation of WebApplicationInitializer named AbstractDispatcherServletInitializer makes it even easier to register the DispatcherServlet by simply overriding methods to specify the servlet mapping and the location of the DispatcherServlet configuration.  
  • This is from Spring 3.1+
Lets now see the Java config -


public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
    
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

        rootContext.register(RootApplicationConfig.class);
       
        container.addListener(new ContextLoaderListener(rootContext));
       
        AnnotationConfigWebApplicationContext displacherContext = new AnnotationConfigWebApplicationContext();
        displacherContext.register(MyWebConfig.class);
    
    
        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(displacherContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
} 


Code for MyWebConfig.java and RootApplicationConfig.java are given below -

Or as I mentioned before you can extend abstract class AbstractDispatcherServletInitializer.

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
        return cxt;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }


Now you don't need web.xml as part of your web application. Your container will startup your app using Java config provided. This classes are detected automatically.

 RootApplicationConfig.java

 package com.osfg.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * 
 * @author athakur
 * Root applciation context
 * Services and data sources should go here - common to all web application contexts
 */
@Configuration
@ComponentScan({ "com.osfg" })
@PropertySource(value = { "classpath:com/osfg/resources/spring-props.properties" })
public class RootApplicationConfig {


}


Source :  https://github.com/aniket91/SpringFeaturesDemo/blob/master/src/com/osfg/config/RootApplicationConfig.java



MyWebConfig.java

package com.osfg.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * 
 * @author athakur
 * Dispacher servlet context - web app context
 * All Controllers. handler mappings, viewresolvers etc should go here
 */
@Configuration
@ComponentScan({ "com.osfg.controllers" })
@EnableWebMvc
public class MyWebConfig {
    
    @Bean
    public ViewResolver getViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

}


Source : https://github.com/aniket91/SpringFeaturesDemo/blob/master/src/com/osfg/config/MyWebConfig.java


 You can see the complete sample code in my github repo -



If you are not using Spring you will need to do -

  1. Create a custom class that implements ServletContainerInitializer (i.e. com.osfg.MyServletContainer
  2. Create a file in your META-INF/services folder named javax.servlet.ServletContainerInitializer which will contain the name of your implementation above (com.osfg.MyServletContainer)
In Spring ofcourse you don't need to do this.

Related Links

t> UA-39527780-1 back to top