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 ...
随机推荐
- UBUNTU 16.04 LTS SERVER 手动升级 MariaDB 到最新版 10.2
UBUNTU 16.04 LTS SERVER 手动升级 MariaDB 到最新版 10.2 1. 起因 最近因为不同软件的数据问题本来只是一些小事弄着弄着就越弄越麻烦了,期间有这么个需求,没看到有中 ...
- Beego和Vue的前后端分离跨域问题处理
VUE封装的请求头(注意请求头,跨域要用到) 路径 utils/mereq.js import request from '@/utils/request' import qs from 'qs' e ...
- jvm源码解读--18 Java的start()方法解读 以及 wait 和notify流程图
drawwed by 张艳涛 and get info from openjdk8 还有一个图
- Unity3D学习笔记3——Unity Shader的初步使用
目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...
- Map 与 unordered_map 横向与纵向测试,附带原始数据与测试程序
写程序时,面临用Map还是unordered_map,总是很纠结,于是写了个程序进行测试 Map 与 unordered_map 横向与纵向测试,附带原始数据与测试程序 简单数据(4 Byte) 首先 ...
- goproxy.io
goproxy.io 是全球最早的 Go modules 镜像代理服务之一, 采用 CDN 加速服务为开发者提供依赖下载, 该服务由一批热爱开源, 热爱 Go 语言的年轻人开发维护.从 Go 1.11 ...
- Docker部署ELK之部署logstash7.6.0(4)
前言: logstash 和filebeat都具有日志收集功能,filebeat更轻量,占用资源更少,但logstash 具有filter功能,能过滤分析日志.一般结构都是filebeat采集日志,然 ...
- 给 Arm 生态添把火,腾讯 Kona JDK Arm 架构优化实践
前言 Arm 架构以其兼具性能与功耗的特点,在智能终端以及嵌入式领域得到了广泛的使用,不断扩大其影响力.而在 PC 端以及数据中心,之前往往是 x86 架构在其中发挥着主要的作用.最近,随着人工智能. ...
- JavaScript学习05(操作DOM)
操作DOM DOM(文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被结构化为对象树: 通过这个对象模型,Java ...
- WPS:利用数据透视表将数据按指定列进行分组求和
1.场景 如图所示:根据日期计算日期当天的总金额 2.利用数据透视表完成该操作 (1)选择金额列的某一格数据,点击上方插入--数据透视表 !!请确保表格第一行为表头 (2)在弹出的页面中直接点击&qu ...