摘要:概述本章我们主要分析处理组件的处理流程以及其接口源码。概括来说,使用组件分为两步,首先是注册组件,其次是处理用户请求,以下针对这两个过程进行详细的分析。本系列文章是基于。接下来的几章将分析提供的适配策略,希望本节对大家能有帮助,谢谢。
概述
本章我们主要分析Spring处理HandlerAdapter组件的处理流程以及其接口源码。概括来说,Spring使用HandlerAdapter组件分为两步,首先是注册组件,其次是处理用户请求,以下针对这两个过程进行详细的分析。
本系列文章是基于Spring5.0.5RELEASE。
注册HandlerAdapter一般情况下,在使用Spring MVC时,我们会配置在应用启动时加载和初始化Spring MVC组件,也就是在部署描述文件中配置
/**
* 初始化策略对象
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
// 初始化处理器适配器HandlerAdapter
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// 在部署描述文件中可控制该参数
if (this.detectAllHandlerAdapters) {
// 从应用上下文中查找HandlerAdapter
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// 对使用的HandlerAdapter进行排序,spring提供的只有RequestMappingHandlerAdapter实现了Ordered接口,其他都不具备排序功能
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
// 如果在部署描述文件中配置了detectAllHandlerAdapters=false,此时spring会加载名称为handlerAdapter的bean为处理器适配器
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
// 转化为集合赋给handlerAdapters属性
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we"ll add a default HandlerAdapter later.
}
}
// 如果未配置HandlerAdapter,注册默认的处理器适配器,即从DispatcherServlet.properties中获取的HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和ReqeustMappingHandlerAdapter
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet "" + getServletName() + "": using default");
}
}
}
以上就是Spring MVC对HandlerAdapter组件的注册过程。
处理请求应用在启动时完成了HandlerAdapter的注册,即具备了处理用户请求的能力,那么在用户发起请求时,请求会有DispatcherSerlvlet所拦截,最终调用其doDispatch方法进行处理,源码如下:
/**
* 处理请求分发给handler
*/
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 {
// 附件上传有关,后续分析multipartResolver时再详细分析
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取请求处理的HandlerExecutionChain对象,该对象组装了我们的handler和相关拦截器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取请求处理的处理器适配器,在getHandlerAdapter方法中进行适配策略的判断
// 参加下面getHandlerAdapter的方法详解
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 拦截器处理用户请求,即执行请求相关的拦截器方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用handler处理方法,由此,通过适配器模式就调用到了我们使用的handler的处理方法
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);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
/**
* 返回handler对象的处理器适配器
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
// 迭代处理器适配器策略,判断handler是否适配成功
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
// 进行适配策略的判断
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
以上就是HandlerAdatper处理用户请求源码分析。
接口分析通过前面两部分,我们分析了Spring MVC对HandlerAdapter组件的使用,包括注册和处理请求过程,接下来我们看一下给接口的定义,源码如下:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
public interface HandlerAdapter {
/**
* 判断适配器是否适配handler,适配策略由子类实现
*/
boolean supports(Object handler);
/*
* 使用适配的handler执行用户请求
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 返回资源的最后修改时间,如果handler实现类不支持可以返回-1
*/
long getLastModified(HttpServletRequest request, Object handler);
}
以上是HandlerAdapter接口的源码分析,如需自定义HandlerAdapter,只需要实现该接口,在supports方法中定义适配策略,并实现handle方法进行调用即可。
总结本文主要分析了Spring MVC使用HandlerAdapter组件处理用户请求的过程,从过程来看,用户可干预的也就是实现HanderApater接口,自定义处理器适配器。
接下来的几章将分析Spring MVC提供的HandlerAdapter适配策略,希望本节对大家能有帮助,谢谢。
最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69547.html
摘要:本系列文章是基于。说这么多就是想解释下什么是适配器。本节我们主要从整体以及概念上阐述了的,后续会逐个分析提供的四种适配器,希望本节对大家能有帮助,谢谢。最后创建了群方便大家交流,可扫描加入,同时也可加我,共同学习共同进步,谢谢 概述 本章开始,我们分析Spring MVC的另一个重要组件,即HandlerAdapter,从命名上我即可直观的理解为处理器适配器,那么处理器适配器是什么意思...
摘要:概述回顾上两章,我们主要分析了的概念作业以及如何使用的组件,本节以及后续几章,将介绍为我们提供的的具体实现类,基于源码和设计层面进行介绍,欢迎大家关注。本系列文章是基于。 概述 回顾上两章,我们主要分析了HandlerAdapter的概念、作业以及Spring MVC如何使用的HandlerAdapter组件,本节以及后续几章,将介绍Spring为我们提供的HandlerAdapter...
摘要:问题来了,我们到底还在用吗答案是,不全用。后者是初始化的配置,主要是的配置。启动类测试启动项目后,在浏览器里面输入。通过查询已装载的,并且支持该而获取的。按照前面对的描述,对于而言,这个必定是。的核心在的方法中。 之前已经分析过了Spring的IOC(《零基础带你看Spring源码——IOC控制反转》)与AOP(《从源码入手,一文带你读懂Spring AOP面向切面编程》)的源码,本次...
摘要:概述本章开始进入另一重要的组件,即视图组件,处理视图组件使用两个主要的接口是和。接口的作用是用于处理视图进行渲染。延用之前的介绍流程,本章分两部分进行阐述启动初始化和请求处理。 概述 本章开始进入另一重要的组件,即视图组件,Spring MVC处理视图组件使用两个主要的接口是ViewResolver和View。根据名称可知,ViewResolver即视图解析器,其作用是把逻辑视图名称解...
摘要:处理器是继前端控制器的后端控制器,在的控制下对具体的用户请求进行处理。由于涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发。 1、mcv整体架构和流程 showImg(https://segmentfault.com/img/bV55Qq?w=860&h=406); 用户发送请求至前端控制器 DispatcherServlet DispatcherServlet 收到...
阅读 3304·2021-09-30 09:47
阅读 2214·2021-09-22 16:04
阅读 2563·2021-09-22 15:44
阅读 2771·2021-08-25 09:38
阅读 771·2019-08-26 13:23
阅读 1412·2019-08-26 12:20
阅读 2992·2019-08-26 11:59
阅读 1338·2019-08-23 18:40