Spring MVC Introduction, Core Principles, and Source Code Analysis
This article introduces Spring MVC, explains the problems of mixing JSP and Servlets, details the MVC layered architecture, walks through essential configuration files and Maven dependencies, presents sample controller code, and analyzes the DispatcherServlet source to illustrate the complete request‑response flow in a Java web application.
Spring MVC Introduction
Spring MVC is a core component of the SSM framework used to separate front‑end and back‑end code, replacing the tightly coupled JSP‑Servlet model with a clean three‑layer MVC architecture.
Problems with JSP/Servlet Mixing
Old projects often mixed HTML and Java code, causing heavy coupling, difficult maintenance, and poor testability. The solution is to strictly separate concerns into presentation, controller, service, and persistence layers.
Spring MVC Architecture
The framework introduces a front‑controller DispatcherServlet that dispatches requests to custom controllers. Core components include:
DispatcherServlet : global request dispatcher.
HandlerMapping : maps URLs to handler chains (interceptors + controller).
HandlerAdapter : invokes the appropriate controller via reflection.
Handler (the controller itself).
ModelAndView : holds model data and logical view name.
View : resolves the logical view to a physical view for rendering.
Project Setup and Configuration Files
Using Maven, create an SSM project with the following configuration files placed under src/main/resources :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
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.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.ldc.model"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.ldc.dao"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>The accompanying jdbc.properties defines database connection details, while log4j.properties sets up simple logging.
# Log output level
log4j.rootLogger=debug,stdout,D,E
# Console appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} -[%p] method:[%c (%rms)] - %m%nThe Spring MVC specific file spring-mvc.xml enables annotation‑driven controllers, component scanning, and view resolution:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.ldc"/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>The web.xml registers the DispatcherServlet , character encoding filter, and links the Spring configuration files:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>mvcDemo</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>Sample Controller
A simple UserController demonstrates typical Spring MVC annotations:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
@RequestMapping("/getUserById")
public ModelAndView selectUser(@PathVariable("id") Long id) throws Exception {
ModelAndView mv = new ModelAndView();
User user = userService.selectUser(id);
mv.addObject("user", user);
mv.setViewName("user");
return mv;
}
}The annotations indicate controller role, request mapping, and dependency injection.
DispatcherServlet Source Code Analysis
The core method doDispatch(HttpServletRequest request, HttpServletResponse response) orchestrates the whole request lifecycle:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
try {
ModelAndView mv;
boolean errorView = false;
try {
// multipart check
processedRequest = checkMultipart(request);
// 1. Find handler via HandlerMapping
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. Get appropriate HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. Invoke handler (controller) -> obtain ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// view name translation if needed
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
} catch (ModelAndViewDefiningException ex) {
logger.debug("ModelAndViewDefiningException encountered", ex);
mv = ex.getModelAndView();
} catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
// 4. Render view
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling");
}
}
// afterCompletion of interceptors
} catch (Exception ex) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
} catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
} finally {
if (processedRequest != request) {
cleanupMultipart(processedRequest);
}
}
}The method performs multipart handling, handler mapping, adapter selection, controller invocation via reflection, interceptor pre‑ and post‑processing, view resolution, and final rendering.
Subsequent sections walk through how HandlerMapping builds a HandlerExecutionChain , how HandlerAdapter invokes the controller, and how the view is finally rendered, illustrating the complete front‑end → back‑end → front‑end cycle of a Spring MVC request.
Overall, the article provides a practical guide to setting up a simple SSM project, configuring Spring MVC, and understanding the internal flow of requests by examining key source code.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.