Spring Mvc原理分析(一)
Servlet生命周期了解
Servlet的生命(周期)是由容器(eg:Tomcat)管理的,换句话说,Servlet程序员不能用代码控制其生命。
加载和实例化:时机取决于web.xml的定义,如果有x则在容器启动时(eg:SSM),反之则在第一次针对这个Servlet的请求发生时(eg:Spring Boot)。
初始化(init):实例化后会立马进行初始化,也就是执行init方法,init方式只会执行一次。
请求处理:初始化后,Servlet就可以接受请求了,基本方式是执行Servlet接口中的service方法。
终止服务:容器会在合适的时候销毁某个Servlet对象,这个策略取决于容器的开发者/商,销毁时destroy方法会被调用。
核心处理请求流程图
入口
前端控制器DispatcherServlet也是一个Servlet,他父类的父类HttpServletBean覆写了Servlet接口的init方法,在容器第一次加载或者第一次请求时会触发(延迟加载),这个方法是Sring Mvc初始化的入口。
启动初始化
容器启动
- Spring容器启动过程,会执行Bean的加载、创建和初始化,此处以Controller层为例分析,暂不关注其他类型资源。
- RequestMappingHandlerMapping类也是其中一个Bean,负责解析所有标识有@Controller或者@RequestMapping注解的Bean。
- RequestMappingHandlerMapping的父类实现了InitializingBean接口,覆写了afterPropertiesSet()方法,该接口是Spring的扩展点之一,在Bean初始化过程中,所i有属性注入完毕之后,会执行一系列回调(回调入口:AbstractAutowireCapableBeanFactory#initializeBean),其中一个回调会验证当前类是否实现了InitializingBean接口,如果实现了会调用afterPropertiesSet()方法,此方法是解析Controller层路径和方法对应关系的入口。
- 解析完毕之后会存储在AbstractHandlerMethodMapping#MappingRegistry中,控制器方法HandlerMethod存储了当前路径对应方法的主要信息,它只负责准备数据,封装数据,而而不提供具体使用的方式方法。
- 在接收请求时会先根据路径从urlLookup 中获取匹配条件,然后根据匹配条件获取控制器方法HandlerMethod。
class MappingRegistry {
// T:RequestMappingInfo => <请求匹配条件,控制器方法>
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
// T:RequestMappingInfo => <路径,请求匹配条件>
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
}
public class HandlerMethod {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
// Web控制器方法所在的Web控制器bean。可以是字符串,代表bean的名称;也可以是bean实例对象本身。
private final Object bean;
// Bean工程,如果bean属性是Sring的beanName就可以用beanName获取到对应的bean作用Handler
@Nullable
private final BeanFactory beanFactory;
// Web控制器方法所在的Web控制器bean的类型,如果该bean被代理,这里记录的是被代理的用户类信息
private final Class<?> beanType;
// Web控制器方法
private final Method method;
private final Method bridgedMethod;
// Web控制器方法的参数信息:所在类所在方法,参数,索引,参数类型
private final MethodParameter[] parameters;
// 注解@ResponseStatus的code属性
@Nullable
private HttpStatus responseStatus;
// 注解@ResponseStatus的reason属性
@Nullable
private String responseStatusReason;
@Nullable
private HandlerMethod resolvedFromHandlerMethod;
....
}
策略初始化
protected void initStrategies(ApplicationContext context) {
// 初始化文件解析器,用于支持服务器的文件上传
initMultipartResolver(context);
// 初始化国际化解析器,用来提供国际化功能;
initLocaleResolver(context);
// 初始化主题解析器,用来提供皮肤主题功能;
initThemeResolver(context);
// 初始化处理器映射器
initHandlerMappings(context);
// 初始化处理器适配器,为不同的处理器提供上下文运行环境;
initHandlerAdapters(context);
// 处理器异常解析器,用来解析处理器产生的异常;
initHandlerExceptionResolvers(context);
// 初始化视图逻辑名称转换器,根据逻辑视图的名称找到具体的视图。
// 当处理器没有返回逻辑视图名时,将请求的URL自动映射为逻辑视图名;
initRequestToViewNameTranslator(context);
// 初始化视图解析器,当控制器返回后,通过试图解析器会把逻辑视图名进行解析,从而定位实际视图;
initViewResolvers(context);
// 初始化FlashMap管理器接口,负责重定向时,保存参数到临时存储中
initFlashMapManager(context);
}
映射器初始化
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 默认获取应用上下文所有的处理器映射
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 获取所有的处理器映射
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.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
// 根据名称获取指定的bean: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.
if (this.handlerMappings == null) {
// 获取默认的处理器映射
// 从【DispatcherServlet.properties】文件中读取默认配置
// BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
适配器初始化(和映射器逻辑一致)
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
请求处理
流程图
doDispatch方法解析
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 2.获取处理器映射器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
// 获取不到handler 抛异常或者返回404
this.noHandlerFound(processedRequest, response);
return;
}
// 4.获取处理器适配器器
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 6.循环调用拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 8.实际执行代码,handler通过反射执行控制器方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 默认视图
this.applyDefaultViewName(processedRequest, mv);
// 10.循环调用拦截的postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 11.处理结果,进行视图解析 & 模板引擎渲染 & request域填充
// 12.内部会调用拦截器的afterCompletion方法
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
// 目标方法完成之后执行
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
// 目标方法完成之后执行
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
获取处理器映射器
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
// 核心方法获取执行链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取handler
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
// 不满足,返回
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
// 以handler为参数获取执行链:创建一个执行链对象,handler赋值到内部变量,添加所有拦截器
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
...
...
return executionChain;
}
}
获取处理器适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
// 核心判断方法,找到支持该handler的适配器
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
执行拦截器前置处理preHandle方法
HandlerExecutionChain#applyPreHandle
- 拦截器的preHandle方法任意一个返回false则访问不到目标方法
- 拦截器的afterCompletion方法一定会执行
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
// 循环调用
if (!interceptor.preHandle(request, response, this.handler)) {
// 执行完毕拦截器的所有AfterCompletio方法后return
this.triggerAfterCompletion(request, response, (Exception)null);
// 一个返回false即停止循环
return false;
}
}
}
return true;
}
执行控制器的目标方法
InvocableHandlerMethod#doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(this.getBridgedMethod());
try {
// method.invoke(obj,args);
// 反射调用目标类的目标方法
// 目标方法:this.getBridgedMethod()
// this.getBean()获取handler中的bean,即为容器中的目标类实例/可能是一个CGLIB增强后的代理对象
return this.getBridgedMethod().invoke(this.getBean(), args);
} catch (IllegalArgumentException var4) {
this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
throw new IllegalStateException(this.formatInvokeError(text, args), var4);
} catch (InvocationTargetException var5) {
Throwable targetException = var5.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException)targetException;
} else if (targetException instanceof Error) {
throw (Error)targetException;
} else if (targetException instanceof Exception) {
throw (Exception)targetException;
} else {
throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
}
}
}
处理返回结果 & 执行拦截器afterCompletion方法
DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
// a.视图解析 & 模板引擎渲染
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No view rendering, null ModelAndView returned.");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
// b.调用拦截器afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
a.视图解析 & 模板引擎渲染
DispatcherServlet#render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
// 视图解析
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 模板引擎渲染
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
b.调用拦截器afterCompletion方法,一定会执行
HandlerExecutionChain#afterCompletion
public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
同一路径时启动报错源码位置
AbstractHandlerMethodMapping#assertUniqueMethodMapping
private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
// 根据路径信息获取方法信息
// 一个路径对应2个方法时第二个方法解析时会获取到上个方法的信息
HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
// 根据路径获取到方法信息 并且 2个不是同一个方法时报错提示已经存在
if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException(
"Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
newHandlerMethod + "\nto " + mapping + ": There is already '" +
handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
}
}
Spring Mvc原理分析(一)的更多相关文章
- Spring MVC 原理探秘 - 容器的创建过程
1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...
- Spring MVC 原理探秘 - 一个请求的旅行过程
1.简介 在前面的文章中,我较为详细的分析了 Spring IOC 和 AOP 部分的源码,并写成了文章.为了让我的 Spring 源码分析系列文章更为丰富一些,所以从本篇文章开始,我将来向大家介绍一 ...
- spring MVC原理
spring MVC原理 Spring MVC工作流程图 图一 图二 Spring工作流程描述 1. 用户向服务器发送请求,请求被Spring 前端控制Servelt D ...
- Spring学习 6- Spring MVC (Spring MVC原理及配置详解)
百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...
- Spring MVC原理及配置
Spring MVC原理及配置 1. Spring MVC概述 Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得 ...
- Spring事务原理分析-部分二
Spring事务原理分析-部分二 说明:这是我在蚂蚁课堂学习了余老师Spring手写框架的课程的一些笔记,部分代码代码会用到余老师的课件代码.这不是广告,是我听了之后觉得很好. 课堂链接:Spring ...
- Spring事务原理分析-部分一
Spring事务原理分析-部分一 什么事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败. 事务基本特性 ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要 ...
- Spring核心原理分析之MVC九大组件(1)
本文节选自<Spring 5核心原理> 1 什么是Spring MVC Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 S ...
- spring之mvc原理分析及简单模拟实现
在之前的一篇博客中已经简单的实现了spring的IOC和DI功能,本文将在之前的基础上实现mvc功能. 一 什么是MVC MVC简单的说就是一种软件实现的设计模式,将整个系统进行分层,M(model ...
随机推荐
- 《PHP 实现 Base64 编码/解码》笔记
前言 早在去年 11 月底就已经看过<PHP 实现 Base64 编码/解码>这篇文章了,由于当时所掌握的位运算知识过于薄弱,所以就算是看过几遍也是囫囵吞枣一般,不出几日便忘记了其滋味. ...
- 在Vue中echarts可视化组件的使用
echarts组件官网地址:https://echarts.apache.org/examples/zh/index.html 1.找到脚手架项目所在地址,执行cnpm install echarts ...
- [SHOI2014]概率充电器 题解
注意到本题的贡献是不带权的,所以期望其实就是每个点的概率之和. 本题正着做好像不是很好做,要考虑 \(P(A+B)=P(A)+P(B)-P(A)P(B)\) 的容斥(因为这是两个条件至少满足一个,所以 ...
- jenkens安装教程
war包安装方式(linux和windows下) 具体参见:https://www.cnblogs.com/UncleYong/p/10742867.html
- 【阿菜用工具】利用 Web3.js 在 ganache 上部署以及调用智能合约
合约部署 要部署的合约 pragma solidity ^0.4.23; contract test { uint256 value; function setValue(uint256 _value ...
- 论文笔记:(2019)GAPNet: Graph Attention based Point Neural Network for Exploiting Local Feature of Point Cloud
目录 摘要 一.引言 二.相关工作 基于体素网格的特征学习 直接从非结构化点云中学习特征 从多视图模型中学习特征 几何深度学习的学习特征 三.GAPNet架构 3.1 GAPLayer 局部结构表示 ...
- 【Azure 应用服务】Azure Function HTTP 触发后, 230秒就超时。而其他方式触发的Function, 执行5分钟后也超时,如何调整超时时间?
问题描述 Azure Function HTTP 触发后, 230秒就超时,而其他方式触发的Function, 执行5分钟后也超时,如何调整超时时间? 问题分析 查阅官方文档,对函数应用超时持续时间有 ...
- 对象转换工具 MapStruct 介绍
前言 在我们日常开发的分层结构的应用程序中,为了各层之间互相解耦,一般都会定义不同的对象用来在不同层之间传递数据,因此,就有了各种 XXXDTO.XXXVO.XXXBO 等基于数据库对象派生出来的对象 ...
- expect命令和here document免交互
目录 一.Here Document免交互 1.1 概述 1.2 语法格式 1.3 简单案例 1.4 支持变量替换 1.5 多行注释 1.6 完成自动划分磁盘免交互 二.Expect进行免交互 2.1 ...
- Notes of Cygwin in Windows7
Installation download setup.exe from its official website; run setup.exe, select "download with ...