SpringMVC_第四部分 Spring MVC 源码深度剖析

SpringMVC_第四部分 Spring MVC 源码深度剖析

1 节 前端控制器 DispatcherServlet 继承结构

 

2 节 重要时机点分析

1 Handler ⽅法的执⾏时机

 打断点

观察调⽤栈

 

doDispathch ⽅法中的 1064 ⾏代码完成 handler ⽅法的调⽤
2 )⻚⾯渲染时机(打断点并观察调⽤栈)

 

SpringMVC 处理请求的流程即为
org.springframework.web.servlet.DispatcherServlet#doDispatch ⽅法的执⾏过程,其中步骤
2 3 4 5 是核⼼步骤
1 )调⽤ getHandler() 获取到能够处理当前请求的执⾏链 HandlerExecutionChain Handler+ 拦截
器) 但是如何去 getHandler 的?后⾯进⾏分析
2 )调⽤ getHandlerAdapter() ;获取能够执⾏ 1 )中 Handler 的适配器
但是如何去 getHandlerAdapter 的?后⾯进⾏分析
3 )适配器调⽤ Handler 执⾏ ha.handle (总会返回⼀个 ModelAndView 对象)
4 )调⽤ processDispatchResult() ⽅法完成视图渲染跳转
protected void doDispatch ( HttpServletRequest request , HttpServletResponse
response ) throws Exception {
HttpServletRequest processedRequest = request ;
HandlerExecutionChain mappedHandler = null ;
boolean multipartRequestParsed = false ;
WebAsyncManager asyncManager = WebAsyncUtils . getAsyncManager ( request );
try {
ModelAndView mv = null ;
Exception dispatchException = null ;
try {
// 1 检查是否是⽂件上传的请求
processedRequest = checkMultipart ( request );
multipartRequestParsed = ( processedRequest != request );
// Determine handler for the current request.
/*
2 取得处理当前请求的 Controller ,这⾥也称为 Handler ,即处理器
这⾥并不是直接返回 Controller ,⽽是返回 HandlerExecutionChain 请求处
理链对象
该对象封装了 Handler Inteceptor
*/
mappedHandler = getHandler ( processedRequest );
if ( mappedHandler == null ) {
// 如果 handler 为空,则返回 404
noHandlerFound ( processedRequest , response );
return ;
}
// Determine handler adapter for the current request.
// 3 获取处理请求的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter ( mappedHandler . getHandler ());
// Process last-modified header, if supported by the handler.
// 处理 last-modified 请求头
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 ;
}
}
if ( ! mappedHandler . applyPreHandle ( processedRequest , response )) {
return ;
}
// Actually invoke the handler.
// 4 实际处理器处理请求,返回结果视图对象
mv = ha . handle ( processedRequest , response ,
mappedHandler . getHandler ());
if ( asyncManager . isConcurrentHandlingStarted ()) {
return ;
}
// 结果视图对象的处理
applyDefaultViewName ( processedRequest , mv );
mappedHandler . applyPostHandle ( processedRequest , response , mv );
}
catch ( Exception ex ) {
dispatchException = ex ;
}
catch ( Throwable err ) {
// As of 4.3, we're processing Errors thrown from handler methods
as well,
// making them available for @ExceptionHandler methods and other
scenarios.
dispatchException = new NestedServletException ( "Handler dispatch
failed" , err );
}
// 5 跳转⻚⾯,渲染视图
processDispatchResult ( processedRequest , response , mappedHandler , mv ,
dispatchException );
}
catch ( Exception ex ) {
// 最终会调⽤ HandlerInterceptor afterCompletion ⽅法
triggerAfterCompletion ( processedRequest , response , mappedHandler ,
ex );
}
catch ( Throwable err ) {
// 最终会调⽤ HandlerInterceptor afterCompletion ⽅法
triggerAfterCompletion ( processedRequest , response , mappedHandler ,
new NestedServletException ( "Handler processing failed" , err ));
}
finally {
if ( asyncManager . isConcurrentHandlingStarted ()) {
// Instead of postHandle and afterCompletion
if ( mappedHandler != null ) {
mappedHandler . applyAfterConcurrentHandlingStarted ( processedRequest ,
response );
}
}
else {
// Clean up any resources used by a multipart request.
if ( multipartRequestParsed ) {
cleanupMultipart ( processedRequest );
}
}
}
}

3 节 核⼼步骤getHandler⽅法剖析

遍历两个 HandlerMapping ,试图获取能够处理当前请求的执⾏链

 

4 节 核⼼步骤getHandlerAdapter⽅法剖析

遍历各个 HandlerAdapter ,看哪个 Adapter ⽀持处理当前 Handler

 

5 节 核⼼步骤ha.handle⽅法剖析

⼊⼝

 

断点从⼊⼝进⼊

 

 

 

 

6 节 核⼼步骤processDispatchResult⽅法剖析render⽅法完成渲染

render ⽅法完成渲染

 

视图解析器解析出 View 视图对象

 

在解析出 View 视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的
View 实现

 解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名

封装View视图对象之后,调⽤了view对象的render⽅法 

 渲染数据

modelMap 中的数据暴露到 request 域中,这也是为什么后台 model.add 之后在 jsp 中可以从请求
域取出来的根本原因

 

 将数据设置到请求域中

 

7 SpringMVC九⼤组件初始化

1)在DispatcherServlet中定义了九个属性,每⼀个属性都对应⼀种组件

/** MultipartResolver used by this servlet. */
// 多部件解析器
@Nullable
private MultipartResolver multipartResolver ;
/** LocaleResolver used by this servlet. */
// 区域化 国际化解析器
@Nullable
private LocaleResolver localeResolver ;
/** ThemeResolver used by this servlet. */
// 主题解析器
@Nullable
private ThemeResolver themeResolver ;
/** List of HandlerMappings used by this servlet. */
// 处理器映射器组件
@Nullable
private List < HandlerMapping > handlerMappings ;
/** List of HandlerAdapters used by this servlet. */
// 处理器适配器组件
@Nullable
private List < HandlerAdapter > handlerAdapters ;
/** List of HandlerExceptionResolvers used by this servlet. */
// 异常解析器组件
@Nullable
private List < HandlerExceptionResolver > handlerExceptionResolvers ;
/** RequestToViewNameTranslator used by this servlet. */
// 默认视图名转换器组件
@Nullable
private RequestToViewNameTranslator viewNameTranslator ;
/** FlashMapManager used by this servlet. */
// flash 属性管理组件
@Nullable
private FlashMapManager flashMapManager ;
/** List of ViewResolvers used by this servlet. */
// 视图解析器
@Nullable
private List < ViewResolver > viewResolvers ;
九⼤组件都是定义了接⼝,接⼝其实就是定义了该组件的规范,⽐如 ViewResolver HandlerAdapter 等都是接⼝

2)九⼤组件的初始化时机

DispatcherServlet 中的 onRefresh() ,该⽅法中初始化了九⼤组件

 

initStrategies ⽅法

 

观察其中的⼀个组件 initHandlerMappings(context)

 

如果按照类型和按照固定 id ioc 容器中找不到对应组件,则会按照默认策略进⾏注册初始化,默
认策略在 DispatcherServlet.properties ⽂件中配置

 

DispatcherServlet.properties

 

注意:多部件解析器的初始化必须按照 id 注册对象( multipartResolver

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC源码包括多个组件和类。其中,Tomcat在启动时会通知Spring初始化容器,加载bean的定义信息并初始化所有单例bean。然后,Spring MVC会遍历容器中的bean,获取每个controller中方法访问的URL,并将URL和Controller保存到一个Map中。这一过程是由HandlerMapping组件完成的,它是Spring MVC中负责URL到Controller映射的组件。此外,在Spring MVC源码中还有一个抽象类FrameworkServlet,它重写了初始化方法initServletBean(),可以在控制台或日志中打印初始化Servlet的名称以及初始化所需的时间。 以上是关于Spring MVC源码的一些重要信息,这些组件和类协同工作,实现了Spring MVC框架的核心功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring MVC源码分析](https://blog.csdn.net/qq_38826019/article/details/117877511)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [SpringMVC源码解析](https://blog.csdn.net/qq_35512802/article/details/120659719)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值