Rahul Kumar
Rahul Kumar

Reputation: 109

Legacy Spring MVC to Spring Boot

I have a legacy application which uses web.xml configuration. The web.xml looks something like this.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring/common-beans-context.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>dispatcherOne</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcherOne-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherOne</servlet-name>
        <url-pattern>/test/*</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>dispatcherTwo</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcherTwo-context.xml</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherTwo</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

To Convert this to Spring Boot Application,

I have done the below changes:

@Bean
    public XmlWebApplicationContext xmlWebApplicationContext() {
        XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
        applicationContext.setConfigLocations("classpath:spring/common-beans-context.xml");
        applicationContext.refresh();
        return applicationContext;
    }

@Bean
    public ServletRegistrationBean<DispatcherServlet> mvcTestServlet(XmlWebApplicationContext applicationContext) {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        // create child application context
        XmlWebApplicationContext childApplicationContext = new XmlWebApplicationContext();
        childApplicationContext.setConfigLocation("classpath:spring/dispatcherOne-context.xml");
        // set parent from the previous method
        childApplicationContext.setParent(applicationContext);
        dispatcherServlet.setApplicationContext(childApplicationContext);
        childApplicationContext.refresh();
        ServletRegistrationBean<DispatcherServlet> servletRegistrationBean = new ServletRegistrationBean<DispatcherServlet>(
                dispatcherServlet, "/test/*");
        servletRegistrationBean.setName("dispatcherOne");
        servletRegistrationBean.addUrlMappings("/test/*");
        servletRegistrationBean.setLoadOnStartup(1);
        return servletRegistrationBean;
    }

    @Bean
    public ServletRegistrationBean<DispatcherServlet> mvcServlet(XmlWebApplicationContext applicationContext) {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        // similar to the previous method..
        // 1. create local applicationContext and then set parent.
    }

I added childApplicationContext.refresh() to see if the beans were loading properly but what i think is happening is that the two dispatcher servlets are not able to access the beans defined in the parentContext. and are throwing beans not found exception even though they're available in parentContext

Is there a workaround for this?

or is there any other way I can achieve this ?

Upvotes: 1

Views: 1258

Answers (1)

M. Deinum
M. Deinum

Reputation: 124536

To create a Spring Boot application and re-using your existing config do the following and don't create a context yourself. You are basically trying to outsmart or work-around Spring Boot with what you are currently doing.

Create a class annotated with @SpringBootApplication and use @ImportResource to let Spring Boot creat the main application context.

@SpringBootApplication
@ImportResource("classpath:spring/common-beans-context.xml")
public YourApplication extends SpringBootServletInitializer {

  public static void main(String[] args) {
    SpringApplication.run(YourApplication.class, args);
  }

  protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    return builder.sources(YourApplication.class);
  } 
}

Now as you have 2 DispatcherServlets in your original config you need to add 2 ServletRegistrationBean to set the URL etc.

@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServletOneRegistration() {
  ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean(new DispatcherServlet(), "/test/*");
  registration.setLoadOnStartup(1);
  registration.setName("dispatcherOne");
  registration.setInitParameters(Collections.singletonMap("contextConfigLocation", "classpath:spring/dispatcherOne-context.xml");
  return registration;
}

And more or less the same for the second servlet.

@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServletTwoRegistration() {
  ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean(new DispatcherServlet(), "/");
  registration.setLoadOnStartup(1);
  registration.setName("dispatcherTwo");
  registration.setInitParameters(Collections.singletonMap("contextConfigLocation", "classpath:spring/dispatcherTwo-context.xml");
  return registration;
}

Upvotes: 2

Related Questions