How to bootstrap a Spring Web MVC application programmatically
- Details
- Written by Nam Ha Minh
- Last Updated on 20 June 2019   |   Print Email
Since Spring framework 3.1+, developers are able to implement a 100% code-based approach for bootstrapping a Spring MVC application, without any XML configuration. This tutorial is going to explore how we can achieve that to build a completely XML-free sample Spring Web MVC application.
Usually we create a Spring’s application context file (e.g. applicationContext.xml) which configures beans definitions such as view resolver beans, controller beans, DAO beans, application-specific beans, etc. And then we declare Spring’s dispatcher servlet in the web deployment descriptor file (web.xml) in order to route all requests through the Spring Web MVC container. For example, following is a typical configuration for bootstrap the Spring’s dispatcher servlet in the web.xml file:
Boostrap a Spring MVC application using XML-based approach:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SpringWebMVCApp</display-name> <servlet> <servlet-name>SpringController</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringController</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
Since Servlet 3.0+, the above registration for Spring’s dispatcher servlet can be done programmatically (code-based), thanks to the Servlet 3.0’s new feature called shared libraries/runtimes pluggability which scans jar files bundled in the WEB-INF\lib directory for implementations of the ServletContainerInitializer interface and invokes its onStartup() method which contains initialization/bootstrapping code, during servlet container/web application startup. In respond to this new feature, Spring 3.1+ provides its own implementation by the SpringServletContainerInitializer class which is bundled in configured in the spring-web-VERSION.jar file.
The SpringServletContainerInitializer class is bootstrapped automatically by any Servlet 3.0-compliant container (e.g. Apache Tomcat 7), and it will look for an implementation of the WebApplicationInitializer interface and invoke its onStartup() method. Following is an example of a WebApplicationInitializer’s implementation that does the same thing as the XML-based approach above:
Bootstrap a Spring MVC application using code-based approach:
import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class SpringWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) throws ServletException { XmlWebApplicationContext appContext = new XmlWebApplicationContext(); appContext.setConfigLocation("/WEB-INF/applicationContext.xml"); ServletRegistration.Dynamic dispatcher = container.addServlet( "SpringDispatcher", new DispatcherServlet(appContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
However, as we can see, the Spring’s application context configuration still remains XML-based:
appContext.setConfigLocation("/WEB-INF/applicationContext.xml");
We may configure the applicationContext.xml file as follows:
XML-based application context configuration:
<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" 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"> <bean name="/" class="net.codejava.spring.HomeController" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
So to replace this XML by a code-based approach, we can create a configuration class using Spring’s @Configuration and @Bean annotations and register this configuration class by the AnnotationConfigWebApplicationContext class.
Here’s an example of a replacement for the applicationContext.xml above in Java code as follows:
Code-based application context configuration:
package net.codejava.spring; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration public class ApplicationContextConfig { @Bean(name = "viewResolver") public InternalResourceViewResolver getViewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Bean(name = "/") public Controller getHomeController() { return new HomeController(); } }
This configuration defines two beans, one for a typical Spring MVC’s view resolver and one for a controller. Code of the HomeController class is as follows:
package net.codejava.spring; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class HomeController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView("home"); } }
The handleRequest() method of this controller class simply returns a logical view name “home” which is mapped to the following home.jsp page:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Spring MVC Bootstrap</title> </head> <body> <div align="center"> <h1>Welcome to Spring MVC Bootstrap demo!</h1> <h3>100% code-based approach, no XML at all!</h3> </div> </body> </html>
And register this configuration file using the AnnotationConfigWebApplicationContext class as follows:
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(ApplicationContextConfig.class);
Then we have our SpringWebAppInitializer class finalized as follows:
100% code-based approach:
package net.codejava.spring; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class SpringWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) throws ServletException { AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); appContext.register(ApplicationContextConfig.class); ServletRegistration.Dynamic dispatcher = container.addServlet( "SpringDispatcher", new DispatcherServlet(appContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
If we build this application in Eclipse IDE, we would have the following project structure:
Package and deploy this application on a Servlet 3.0-compliant server (Apache Tomcat) and access it in browser by the following URL:
http://localhost:8080/SpringMVCBootstrap
Output:
As we can see, this simple Spring Web MVC application is running perfectly! Thanks to the code-based approach, we don’t have to write any XML code at all! One big benefit of this approach is that we can package our application’s bootstrap code in a jar file and put it under WEB-INF\lib directory and the servlet container will automatically detect and initialize it.
Download the sample application (Eclipse project) to test this out yourself.
Related Spring Tutorials:
- How to enable Spring MVC in web.xml
- Understand the core of Spring framework
- Understand Spring MVC
- Understand Spring AOP
- Spring MVC beginner tutorial with Spring Tool Suite
Comments
I am getting the following :
HTTP Status 404 - /SpringMVCBootstrap/
type Status report
message /SpringMVCBootstrap/
description The requested resource (/SpringMVCBootstrap/) is not available.
Maybe the application failed to start. What did you see in the server's error log file?
while i am running this code it showing runtime exception.
EXCEPTION
java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:170)
I think problem in SpringWebAppInitializer class