Migrate Spring MVC servlet.xml to Java Config

Since Spring 3, Java configuration (@Configuration) has been moved into spring-core and has caught my attention. This is a quick sample of how to convert an existing servlet.xml file into a java config file.

Beginning xml

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

    <!-- Scan for spring annotated components -->
    <context:component-scan base-package="com.luckyryan.sample"/>

    <!-- Process annotations on registered beans like @Autowired... -->
    <context:annotation-config/>

    <!-- This tag registers the DefaultAnnotationHandlerMapping and
         AnnotationMethodHandlerAdapter beans that are required for Spring MVC  -->
    <mvc:annotation-driven/>

    <!-- Exception Resolver that resolves exceptions through @ExceptionHandler methods -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"/>

    <!-- View Resolver for JSPs -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- This tag allows for mapping the DispatcherServlet to "/" -->
    <mvc:default-servlet-handler/>

    <!-- resources exclusions from servlet mapping -->
    <mvc:resources mapping="/assets/**" location="classpath:/META-INF/resources/webjars/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/img/**" location="/img/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>

</beans>

1. Create the configuration class, I like to create a “config” package with a class named appConfig.java
2. Add @Configuration, this will let spring know this contains bean definitions.

package com.luckyryan.sample.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class appConfig {

}

3. Add @EnableWebMVC, this is the same as <mvc:annotation-driven/>

@EnableWebMvc
@Configuration
public class appConfig {

}

4. Add @ComponentScan(basePackages = {“com.luckyryan.sample”}), this is the same as <context:component-scan base-package=”com.luckyryan.sample”/>

@EnableWebMvc
@ComponentScan(basePackages = {"com.luckyryan.sample"})
@Configuration
public class appConfig {

}

5. Extend the class to use WebMvcConfigurerAdapter. This adds stub implementations from the WebMvcConfigurer interface which is used by @EnableWebMVC. It also gives us a chance to override resources and the default handler.

@EnableWebMvc
@ComponentScan(basePackages = {"com.luckyryan.sample"})
@Configuration
public class appConfig extends WebMvcConfigurerAdapter {

}

6. Declare our static resources. I added cache to the java config but it’s not required.

@EnableWebMvc
@ComponentScan(basePackages = {"com.luckyryan.sample"})
@Configuration
public class appConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    	registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
    	registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
    	registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
    	registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
 	}

}

7. Set default servlet handler, this is the same as <mvc:default-servlet-handler/>

@EnableWebMvc
@ComponentScan(basePackages = {"com.luckyryan.sample"})
@Configuration
public class appConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

8. Add bean for InternalResourceViewResolver

package com.luckyryan.sample.config;

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

@EnableWebMvc
@ComponentScan(basePackages = {"com.luckyryan.sample"})
@Configuration
public class appConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

9. Update the servlet declaration in web.xml for the new config class and annotation conf. Note: this replaces the need for <context:annotation-config/> which was not featured in the servlet.xml example.

...
...
<servlet>
    <servlet-name>sample</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.luckyryan.sample.config.appConfig
        </param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>sample</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Posted in Spring MVC Tagged with: ,
19 comments on “Migrate Spring MVC servlet.xml to Java Config
  1. Excellent post
    Thanks for the mentioned resources
    And “extends WebMvcConfigurerAdapter” it was really useful

  2. kumar says:

    Thanks Ryan,
    Really very Good post & Explaination.Thanks again!

    Ryan,I am new to Spring MVC.I want to build a small application based on Spring 3.2 MVC with no involvement of XML & without using Mavan.just using STS.
    Can you explain in depth with sample code ? so that it helps for other people like me

    • Alabama Mothman says:

      When I was new to spring, I tried to use spring without maven.

      The versions are too tightly wrapped with hibernate and I could never get it to run. Almost gave up on spring. But maven is no panacea for spring.

      Having said all that though, JSF is vastly superior to spring. Spring mvc is not even mvc. You still have to interweave logic in the jsp. In my opinion Spring is too difficult for people to learn how to manage and leads to very bad coding(hardcoding) practices. Even Maven has it’s difficulties with it.

  3. Emanuele says:

    Really good guide, tnx.

  4. dever says:

    Thanks from me too Ryan – that was just what I needed and worked a treat – now to write the logic on my controllers

  5. Rick says:

    Sorry, mangled that. Do you know how to migrate this:

    <jsp-config>
    <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
    </jsp-config>

    • Ryan says:

      Excellent question, I don’t know of a specific way. There is Spring’s CharacterEncodingFilter but that is still defined as a Servlet filter in the web.xml and won’t fully give you what you are looking for. Other than that I would guess a MVC interceptor to set specifics on the request could work. Still seems like a bad hack. Sorry I don’t have a better answer but will update the thread if I find something.

  6. Rod Woo says:

    Exactly what I needed. Thanks!

  7. Abilash says:

    This really helped me. I was looking for this so long. Thanks!!

  8. pushkar says:

    Thanks for the guide. I tried migration. I am getting an exception on application startup. Apparently it still expects an applicationContext.xml

    • Ryan says:

      Double check the web.xml. The new servlet definition (org.springframework.web.servlet.DispatcherServlet) should use contextClass org.springframework.web.context.support.AnnotationConfigWebApplicationContext and define the location of the Java class that has the correct annotations. The old reference should be removed. Also check that context-param locations does not define applicationContext.xml.

  9. Rambabu says:

    Thank you very much Ryan..

  10. Al Mathews says:

    Thanks for the post. Very helpful.

  11. Kitty says:

    Hey Ryan. Can you plz explain how to migrate JDBC connection bean.

    </bean

  12. Hassan says:

    Very useful post. It resolved me one issue about the static resources. Thanks :)

    Hassan

  13. Yuva says:

    Ryan, thanks for this excellent write-up.

  14. anand says:

    awesome, hhelpful, thanks!

  15. Alabama Mothman says:

    Great work, but, why would you want to do this?

    I can see no advantage of hardcoding your configuration. What about dependency injection. What would you do for that?

  16. Thrawn says:

    If you’re going to move to JavaConfig, then you may as well ditch web.xml entirely and use a WebApplicationInitializer:

    http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>