Spring MVC源码剖析
Spring MVC简介
MVC体系结构
- 三层架构
我们的开发架构一般都是基于两种形式,一种是C/S架构(客户端/服务器),另一种是B/S架构(浏览器/服务器)。在JavaEE开发中,几乎全部都是基于B/S架构的开发。在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。 - MVC设计模式
MVC全名是Model View Controller,是 模型(Model)-视图(View)-控制器(Controller)的缩写,是一种用于设计创建Web应用程序表现层的模式。MVC中每个部分各司其职:- Model:模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。
- View:通常指jsp或者html,用于展示数据,通常视图时依据数据模型创建的
- Controller:是应用程序中处理用户交互的部分,用于处理程序逻辑的。
MVC提倡:每一层只编写自己的东西,不编写任何其他代码;分层是为了解耦,解耦是为了维护方便和分工协作。
Spring MVC是什么
Spring MVC全面是Spring Web MVC,是一种基于java实现的MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。
Spring MVC工作流程
Spring MVC 请求处理流程
流程说明
- 第一步:用户发送请求至前端控制器DispatcherServlet
- 第二部:DispathcerServlet收到请求调用HanlderMapping处理器映射器
- 第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),生成处理器对象及处理器拦截器一并返回DispatcherServlet
- 第四步:DispathcerServlet调用HandlerAdapter处理器适配器去调用Handler
- 第五步:处理器适配器执行Hanlder
- 第六步:Hanlder执行完成给处理器适配器返回ModelAndView
- 第七步:处理器适配器向前端控制器返回ModelAndView
- 第八步:前端控制器请求ViewResolver视图解析器,解析视图
- 第九步:视图解析器解析完毕返回View视图
- 第十步:前端控制器进行视图渲染,将模型数据填充到request中
- 第十一步:前端控制器向用户响应结果
Spring MVC九大组件
- HanlderMapping(处理器映射器)
HandlerMapping是用来查找Hanlder处理器的 - HandlerAdapter(处理器适配器)
HandlerAdapter是一个适配器,适配具体处理请求的Hanlder - HandlerExceptionResolver(处理器异常解析器)
HandlerExceptionResolver是用于处理Handler产生的异常情况 - ViewResolver(视图解析器)
ViewResolver是视图解析器,用于找到渲染所用的模板和所用视图并填入数据。 - RequesetToViewNameTranslator(请求-视图名称转换器)
RequesetToViewNameTranslator作用是从请求中获取VIewName。ViewResolver是根据ViewName查找View,若Hanlder处理完成之后没有设置View,也没有设置ViewName,那么就是通过该组件从请求中查找ViewName - LocalResolver(本地语言环境解析器)
LocalResolver是支持国际化的组件 - ThemeResolver(主题解析器)
ThemResolver组件是用来解析主题的,即各种样式、图片等 - MultipartResolver(多部件解析器,文件上传)
MultipartResolver适用于上传请求,通过将普通请求包装成MultipartHttpServletRequest来实现。 - FlashMapManager(FlashMap管理器)
FlashMap用于重定向时的参数传递。
Spring MVC源码剖析
前端控制器DispatcherServlet继承结构
重要时机点分析
- Hanlder方法的执行时机
在controller的方法中打断点,观察调用栈
doDispatch方法中1040行完成handle方法调用 - Spring MVC处理请求的流程为org.springframework.web.servlet.DispatcherServlet#doDispatch方法的执行过程,其中步骤2、3、4、5是核心步骤
1、调⽤getHandler()获取到能够处理当前请求的执⾏链 HandlerExecutionChain(Handler+拦截器)
2、⽤getHandlerAdapter();获取能够执⾏1中Handler的适配器
3、适配器调⽤Handler执⾏ha.handle(总会返回⼀个ModelAndView对象)
4、调⽤processDispatchResult()⽅法完成视图渲染跳转
核心步骤getHandler方法剖析
在DispatcherSerlvet调用getHanlder方法处打断点
进入getHandler方法
遍历handlerMappings,获取能够处理当前请求的执行链
核心步骤getHandlerAdapter方法剖析
如getHandler一样,在调用getHandlerAdapter方法处打断点
进入getHandlerAdapter方法
遍历handlerAdapters,获取支持处理当前Handler的Adapter
核心步骤ha.handle方法剖析
在调用Handler的handle方法处打断点
进入方法查看具体执行流程
适配具体Handler
执行方法
核心步骤processDispatchResult方法剖析
如上述相同步骤,观察执行过程
视图解析器解析处View视图对象
在解析出View视图对象的过程中,会判断是否重定向,是否转发等,不同情况封装不同的View实现
解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名
封装View视图对象之后,调用View对象的render方法
渲染数据
把modelMap中的数据暴露到request域中
将数据设置到请求域中
Spring MVC九大组件初始化
- 在DispatcherServlet中定义了九个属性,每一个属性都对应一种组件
/** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
// 多部件解析器
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
/** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
// 区域化(国际化)解析器
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
/** Well-known name for the ThemeResolver object in the bean factory for this namespace. */
// 主题解析器
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
/**
* Well-known name for the HandlerMapping object in the bean factory for this namespace.
* Only used when "detectAllHandlerMappings" is turned off.
* @see #setDetectAllHandlerMappings
*/
// 处理器映射器
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
/**
* Well-known name for the HandlerAdapter object in the bean factory for this namespace.
* Only used when "detectAllHandlerAdapters" is turned off.
* @see #setDetectAllHandlerAdapters
*/
// 处理器适配器
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
/**
* Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace.
* Only used when "detectAllHandlerExceptionResolvers" is turned off.
* @see #setDetectAllHandlerExceptionResolvers
*/
// 异常解析器
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
/**
* Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace.
*/
// 默认视图名转换器
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
/**
* Well-known name for the ViewResolver object in the bean factory for this namespace.
* Only used when "detectAllViewResolvers" is turned off.
* @see #setDetectAllViewResolvers
*/
// 视图解析器
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
/**
* Well-known name for the FlashMapManager object in the bean factory for this namespace.
*/
// flash属性管理组件
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
九大组件都是定义类接口,接口是定义了规范,我们可以实现自己的各种组件
- 九大组件的初始化时机
/**
* This implementation calls {@link #initStrategies}.
*/
// 该方法调用了初始化策略,初始化了九大组件
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
// 分别调用各个组件初始化方法进行初始化
protected void initStrategies(ApplicationContext context) {
//初始化多部件解析器组件(多用于文件上传)
initMultipartResolver(context);
// 初始化本地语言环境
initLocaleResolver(context);
// 初始化主题处理器
initThemeResolver(context);
// 初始化处理器映射器
initHandlerMappings(context);
// 初始化处理器适配器
initHandlerAdapters(context);
// 初始化处理器异常解析器
initHandlerExceptionResolvers(context);
// 处理请求-视图名称转换器
initRequestToViewNameTranslator(context);
// 处理视图解析器
initViewResolvers(context);
// 初始化FlashMap管理器
initFlashMapManager(context);
}
- 观察其中一个组件initHandlerMappings(conetext)
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 按照HanlderMapping.class类型去IoC容器中找到所有的HandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 对HandlerMapping进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
// 否则在IoC容器中按照固定名称Id(handlerMapping)去找
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
// 确保至少有一个HandlerMapping存在
// 否则按照默认策略生成
if (this.handlerMappings == null) {
// 按照默认方式实例化生成HanlderMapping
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
- 如果按照类型和按照固定Id从IoC容器中找不到对应组件,则会按默认策略进行注册初始化,根据getDefaultStrategies方法中逻辑,默认策略在DispatcherServlet.properties文件中配置
/**
* Create a List of default strategy objects for the given strategy interface.
* <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
* package as the DispatcherServlet class) to determine the class names. It instantiates
* the strategy objects through the context's BeanFactory.
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
*/
@SuppressWarnings("unchecked")
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
// DispatcherServlet.properties
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
}
else {
return new LinkedList<>();
}
}
- DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
文件中包含了八个默认组件的默认实现,其中多部件解析器的初始化必须按照id注册对象(multipartResolver)
// 方法没有去注册默认多部件解析器
private void initMultipartResolver(ApplicationContext context) {
try {
// 通过指定的id从IoC容器中取出对象
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.multipartResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isTraceEnabled()) {
logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
}
}
}