一次Http请求在SpringMvc中的扭转
- 1、用户发送请求至前端控制器DispatcherServlet;
- 2、DispatcherServlet收到请求调用HandlerMapping处理器映射器;
- 3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。(也就是HandlerExecutionChain);
- 4、 DispatcherServlet调用HandlerAdapter处理器适配器;
- 5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器);
- 6、Controller执行完成返回ModelAndView;
- 7、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet;
- 8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器;
- 9、ViewReslover解析后返回具体View;
- 10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中);
- 11、DispatcherServlet响应用户;
相信大家对于上面的步骤并不会陌生,但是在开发过程中是否想过每一个步骤经过那些方法的处理以及为什么要这样处理,对于常用的框架不应该停留在仅仅会使用,知其然也要知其所以然,下面将是鄙人对SpringMVC源码的学习,功力尚浅,如有不当之处,望大佬指点一二!
DispatcherServlet是什么?
根据上面Http请求在SpringMvc中的扭转,我们可以得知它是一个中央控制器,通过idea打开类图可知,这不就是一个实现Servlet接口的的servlet程序,可以用于交互式地浏览和生成数据,生成动态Web内容,通俗可以理解为接收与处理Http请求的应用程序,在这里顺便温习下Servlet的生命周期:
- 1、Servlet 通过调用 init () 方法进行初始化;
- 2、Servlet 调用 service() 方法来处理客户端的请求;
- 3、Servlet 通过调用 destroy() 方法终止(结束);
注意:
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用;
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法;
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用;
用户的请求最先到达就是DispatcherServlet。他是SpringMvc的核心,也是中央出处理器。因此我们分析源码,先看看他是什么样的流程:通过源码可看到:他是继承FrameworkServlet,它也是SpringMvc提供的类,继续往下继承关系看,FrameworkServlet继承HttpServletBean,它依旧是Spring提供的.最终直到他继承HttpServlet;而DispatcherServlet类是Servlet。因此既然是Servlet类,那么它就会去调用service()方法,他是Servlet最核心的方法,但是我们没有在DispatcherServlet中发现有service方法,为此去找父类FrameworkServlet,但是在FrameworkServlet中根据请求方式做了判断,如果请求方式不为PATCH和null就调用HttpService类中找到了service()方法,否则就调用本类的processRequest();
执行service()方法
//FrameworkServlet类
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//HttpMethod枚举,获取请求方式
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
//请求方式不为PATCH和null
if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
//调用父类HttpServlet的service()方法
super.service(request, response);
} else {
//本类的processRequest
this.processRequest(request, response);
}
}
//由于HttpServletBean没有实现Service()方法,于是调用HttpServlet提供的Service()方法
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
this.service(request, response);
}
注意:Tomcat是先调用这个service()方法,将请求对象强转为HttpServletRequest对象,然后再调用service()方法,涉及到方法的重载,至于为什么将ServletRequest-->HttpServletRequest,在次做一个简单的描述,因为HttpServletRequest比ServletRequest多了一些针对于Http协议的方法,比如获取请求方式、请求头等等,HttpServletRequest继承于ServletRequest,可以理解为子类比父类更适合处理Http请求;
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
//由于FrameworkServlet类重写了doPost、doHead等方法,最后都是调用processRequest()
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
小结
由上可知DispatcherServlet类本质是Servlet,那么当请求进来的时候,会调用service()方法,但是它本身并未实现Servlet接口提供的service()方法,于是我们向上级FrameworkServlet(父类)中寻找,在父类中做了判断 如果请求方式不为PATCH和null,就会调用super.service(),但是HttpServletBean(爷爷类)没有实现Service()方法,于是调用HttpServlet(曾祖父)提供的Service()方法,在曾祖父这里先将依据不同的请求方式调用不同的请求方法,但是在不同请求方法中都回到了FrameworkServlet(父类)的processRequest()方法;
FrameworkServlet(父类)processRequest()
//FrameworkServlet类processRequest()
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//拿到之前的LocaleContext上下文(因为可能在Filter里已经设置过了)
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 以当前的request创建一个Local的上下文
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
/**
previousAttributes若为null,或者就是ServletRequestAttributes类型,
那就new ServletRequestAttributes(request, response);
若不为null,就保持之前的绑定结果,不再做重复绑定
*/
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
// 拿到异步管理器。这里是首次获取,会new WebAsyncManager(),然后放到request的attr里面
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//给异步管理器注册RequestBindingInterceptor拦截器
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
//初始化request和Local上下文、RequestContext绑定
this.initContextHolders(request, localeContext, requestAttributes);
try {
//FrameworkServlet类并未实现doService,只有子类实现 模板设计模式
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
//重置上下文
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
//不管doService是否执行成功,都会推送一条消息告知处理事件
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
短暂小结
我们先整体对上面的描述做一次总结,免得在后续的过程思绪混乱;
- 1、当一个请求进来之后,由于DispatcherServlet是一个Servlet对象,但是它本身没有Service()方法,于是调用父类FrameWorkServlet提供的Service( )方法,在这里做了判断:如果请求方式为PATCH && null 就会调用FrameworkServlet类的processRequest();
- 2、如果是其它请求方式,那么就会去请求父类的service()方法,最终调用HttpServlet类中的service()方法,然后根据请求方式不同从而调用不同的方法,最后还是归结于FrameworkServlet类processRequest();
- 3、在processRequest()方法中调用doService()方法,注意FrameworkServlet是一个抽象类,其中声明了doService()抽象方法,具体的逻辑由DispatcherServlet类中doService()实现;
- 4、在processRequest()方法中对请求上下文、参数做了处理,但是在调用doService()处理完成之后,又将request重置,这里待后续再体会作者这样设计的原因;
DispatcherServlet类
既然作为中央控制器,祖宗已经将请求进行各种处理,自己总不能什么都不做吧,含着金钥匙出身也该展现下实力了。。。。。。。
doService()
//DispatcherServlet类中的 doService()方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception{
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
//把一些常用对象放进请求域 方便Handler(处理器)可以随意获取
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
//如果是重定向就需要放置更多的属性
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
//调用doDispatch()方法 最重要的方法,负责分发请求
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
doDispatch()
//DispatcherServlet类中的 doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//根据请求获取异步管理器,就是开始在processRequest()方法中创建的,
在processRequest方法是首次获取,获取不到就直接创建一个
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
//创建一个视图对象
ModelAndView mv = null;
Object dispatchException = null;
try {
// 1. 检查是否是上传文件,如果不是就返回原本的request对象
processedRequest = this.checkMultipart(request);
//不是文件上传,这里就会是false
multipartRequestParsed = processedRequest != request;
// 重点一:通过处理器映射HandlerMapping中获取相应HandlerExecutionChain
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//重点二:获取适配器
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 重点三:通过适配器调用处理器的处理方法并返回ModelAndView视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//进行视图的渲染以及拦截器后置处理
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);
}
}
}
小结
当请求经过祖宗的处理,最后交给了DispatcherServlet类本身,天降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,上来就是通过doService()方法对请求参数补充完整,方便在后续干大事;含着金钥匙出生的就是不一样,以为要自己亲力亲为,没想到这家伙请外援,开始就请了一个大佬来处理执行链对象,等执行链对象获取到之后,又请了另外一个大佬来处理适配器处理器对象,连最后庆祝完成渲染视图都是交给别人处理。。。。
下面我们看看DispatcherServlet是如何请外援干活的;
外援一:获取相应的HandlerExecutionChain(执行链)对象
//HandlerExecutionChain执行链对象的获取
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//initHandlerMappings方法初始化了处理器映射器集合,如何初始化?
//TODO 容器启动时initStrategies方法调用initHandlerMappings方法
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
//遍历处理器映射器集合
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
//获得执行链对象,其中HandlerMapping为接口,由抽象子类AbstractHandlerMapping实现了getHandler方法
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
AbstractHandlerMapping中getHandler()
//如何根据处理器映射器获得处理器? HandlerMapping接口 mapping.getHandler(request)
HandlerMapping是一个接口 其中getHandler()方法由AbstractHandlerMapping类实现
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception{
/*获取 handler 这其实是一个抽象方法
子类可以通过不同实现来获取handler
例如通过 url 和 name的映射逻辑
通过 requestMapping 中的 url 和对应方法的映射逻辑
由具体的子类实现,主要的子类分为抽象子类AbstractHandlerMethodMapping
抽象子类AbstractUrlHandlerMapping
WelcomePageHandlerMapping -继承-> AbstractUrlHandlerMapping
*/
Object handler = this.getHandlerInternal(request);
if (handler == null) {
// 如果获取为null 就采用默认的处理器
handler = this.getDefaultHandler();
}
// 如果还是没有则返回 这时候 DispatcherServlet会返回 404
if (handler == null) {
return null;
} else {
//如果handler为字符串
if (handler instanceof String) {
String handlerName = (String)handler;
//通过beanName从IOC容器中获取相应的处理器 就是在aplication中配置的
handler = this.obtainApplicationContext().getBean(handlerName);
}
//封装执行链对象
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler,request);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Mapped to " + handler);
} else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
this.logger.debug("Mapped to " + executionChain.getHandler());
}
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
// 返回处理器执行链
return executionChain;
}
}
- AbstractHandlerMapping类中getHandlerInternal()
- 可以发现这个方法由三个子类实现 : AbstractHandlerMethodMapping、 AbstractUrlHandlerMapping、 WelcomePageHandlerMapping;
我们主要关注 AbstractHandlerMethodMapping(提供方法处理器)和 AbstractUrlHandlerMapping(提供url对应处理器映射)WelcomePageHandlerMapping属于springBoot提供,继AbstractUrlHandlerMapping;
AbstractUrlHandlerMapping 中的 getHandlerInternal()
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求路径
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
//去handlerMap中寻找,猜想初始化的时候应该做了路径与处理器的映射关系放到一个LinkedHashMap中
Object handler = this.lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = this.getRootHandler();
}
if (rawHandler == null) {
rawHandler = this.getDefaultHandler();
}
if (rawHandler != null) {
if (rawHandler instanceof String) {
String handlerName = (String)rawHandler;
rawHandler = this.obtainApplicationContext().getBean(handlerName);
}
this.validateHandler(rawHandler, request);
handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
}
}
return handler;
}
AbstractHandlerMethodMapping 中的 getHandlerInternal()
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求路径
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
// 上锁因为这个类里面的map很多是非线程安全的
this.mappingRegistry.acquireReadLock();
HandlerMethod var4; //声明一个HandlerMethod对象
try {
/*
重点 通过 lookupHandlerMethod 来从中获取 HandlerMethod
HandlerMethod 是什么?
可以理解为包含了许多请求参数的对象,例如有请求的Controller类\请求方法、请求参数等等
后续会做详细的解读
*/
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
//释放锁
this.mappingRegistry.releaseReadLock();
}
return var4;
}
//构建完整的HandlerMethod对象
public HandlerMethod对象 createWithResolvedBean() {
Object handler = this.bean;
if (this.bean instanceof String) {
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
String beanName = (String)this.bean;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}
/*
通过 lookupHandlerMethod 来从中获取 HandlerMethod HandlerMethod是什么?
通过请求来匹配返回处理器方法,如何通过请求来匹配处理器?
*/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//通过URL,从对应的映射map里面获取requestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 该方法会对requestMappingInfo中的各种条件做匹配,如果匹配对了,则放入matches
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
// 没有匹配到,则遍历所有的requestMappingInfo ,期望能找到一个
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
// 比较找到的matches , 通过requestMappingInfo中的compareTo进行排序
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
// 获取匹配度最高的
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
// 如果第一个和第二个完全一样,那么则要报异常了, 因为两个完全一样的映射,这是有问题的
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回对象
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
封装执行链对象HandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
//调用执行链的构造方法
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[])null);
}
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
this.interceptorIndex = -1;
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain)handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
} else {
//莫非执行器底层是由处理器+拦截器组成?
this.handler = handler;
this.interceptors = interceptors;
}
}
获取执行链小结
在AbstractHandlerMapping中通过不同子类的实现获取到Object类型的handler,为什么使用Object接收,因为Spring需要整合其它框架,可以通过不同方式实现向Web容器中注册servlet,当我们使用@Controller@RequestMapping来定义Controller的时候,就会通过子类AbstractHandlerMethodMapping创建一个HandlerMethod对象来保存请求过程中需要的一些属性,走到这里应该有一个初步的概念;
- 1、通过不同的HandlerMapping获取HandlerExecutionChain对象,HandlerMapping针对各自都有不同的是实现方式;
- 2、HandlerAdapter才是具体执行哪一个HandlerMethod处理业务逻辑;
- 3、可以总结为DispatcherServlet就是分发器,先通过HandlerMapping获取HandlerExecutionChain对象,然后通过HandlerAdapter执行HandlerMethod处理业务逻辑,最后返回视图模型;
- 思考:
当容器初始化的时候在HandlerMapping中维护着一个Map处理Url与Controller的关系,那么在封装HandlerMethod的时候为什么要通过反射来获取请求的参数?是如何使用反射?
向Web容器中注入Serclet的方式有三种:
- a、Web.xml;
- b、写一个类继承Controller类,重写handleRequest方法;
- c、@Controller注解; 那么在DispatchServlet中是怎么获取需要调用哪个Controller?由于Controller本身是一个没有任何继承依赖关系的类,所以采用反射的机制获取;
外援二:获取适配器 HandlerAdapter
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//handlerAdapters在这里也是容器启动时初始化了处理器适配器对象
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
/**
HandlerAdapter也是一个接口,其中supports由不同的子类实现,是不是跟HandlerMapping类同;
主要是根据adapter判断是否支持此handler
其中HandlerAdapter的实现类为:
AbstractHandlerMethodAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
SimpleServletHandlerAdapter
*/
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");
}
由于获取处理器适配器的方式与获取执行链雷同,为此在这里不做过多的描述,在后续学习容器初始化时,是如何实例化处理器适配器时再深入了解;
获取处理器适配器小结
- 1、通过执行链中不同的处理器handler获取处理器适配器,其实可以将执行链对象理解为由handler(处理器)+HandlerInterceptor(拦截器)组成,其中通过@Controller的方式向Web容器中注册servlet,会通过调用 AbstractHandlerMethodMapping方法获得HandlerMethod对象,最后将HandlerMethod对象赋值给HandlerExecutionChain对象中的handler属性;
- 2、在获取处理器适配器时,由于不同适配器对于supports方法有不同的实现方式;
- 3、至于采用什么方式向Web容器中注册servlet,会使用哪个适配器,在后续另作介绍;
外援三:通过适配器调用处理器的处理方法并返回ModelAndView视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
其中通过AbstractHandlerMethodAdapter这个处理器适配的方法
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
@Nullable //由子类RequestMappingHandlerAdapter实现
protected abstract ModelAndView handleInternal(HttpServletRequest var1, HttpServletResponse var2, HandlerMethod var3) throws Exception;
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//检查请求是否合法
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
//执行Controller中方法,返回ModelAndView对象
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
//执行Controller中方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//构建一个ServletWebRequest对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
Object result;
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//执行方法
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (!asyncManager.isConcurrentHandlingStarted()) {
ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
return var15;
}
result = null;
} finally {
webRequest.requestCompleted();
}
return (ModelAndView)result;
}
/**
ServletInvocableHandlerMethod类 中invokeAndHandle()
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取执行Controller之后返回的数据
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//处理返回出去的
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
/**
InvocableHandlerMethod 类中invokeForRequest()
主要是为了通过反射获取请求参数,然后执行Controller方法
*/
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取请求参数
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Arguments: " + Arrays.toString(args));
}
//执行Controller方法
return this.doInvoke(args);
}
/**
通过反射获取请求参数,再次不做过多介绍,在后续中深入了解是如何通过反射获取到请求参数
*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
if (ObjectUtils.isEmpty(this.getMethodParameters())) {
return EMPTY_ARGS;
} else {
MethodParameter[] parameters = this.getMethodParameters();
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String error = var10.getMessage();
if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, error));
}
}
throw var10;
}
}
}
return args;
}
}
/**
执行Controller方法
*/
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(this.getBridgedMethod());
try {
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);
}
}
}
获取ModelAndView小结
我们以通过@Controller注解向Web容器中注入servetl方式进行总结
- 1、这里我们可以根据源码知道,在获取到处理器适配器之后调用处理器适配器中的handle()方法,进行ModelAndView对象的创建;
- 2、在AbstractHandlerMethodAdapter抽象类中只是将handler对象强转为HandlerMethod类型,然后通过子类RequestMappingHandlerAdapter的handleInternal()方法进行ModelAndView对象的创建;
- 3、通过ServletInvocableHandlerMethod的invokeAndHandle()填充数据
- 4、通过RequestMappingHandlerAdapter类getModelAndView()方法构建ModelAndView;
总结
此次学习SpringMVC源码的过程中,还有许多知识与细节点并未涉及到,在后续会继续学习。通过这次初步学习源码与deBug调试,也是不断在发现问题与思考问题,其中有许多设计模式还是未理解,在许多地方也会反思为什么实现框架的人要这样设计?
后续仍需要深入了解的知识:
- 1、容器启动的时候是如何初始化处理器映射器、处理器适配器;
- 2、HandlerMethod这个对象中每个属性的作用是什么;
- 3、不同的方式向Web容器中注册servlet会采用哪个处理器映射期与处理器适配器;
- 4、SpringMVC中是如何维护每个Controller中Mapping映射与方法的关系;
- 5、思考SpringMVC中涉及到的设计模式;
学的越多,发现自己知道的越少,未完待续。。。。。。
致谢
鄙人不才,在您面前献丑只愿与您结伴而行,文章若有不当之处,望大佬指点一二; 如果我对您有帮助的话,还希望您能点赞分享,成长是一场苦涩的独自修行,我很需要您的陪伴与支持,这也是不断前行的根本动力,让我们在互相陪伴见证彼此生长的同时能够感染身边最亲近的人一同成长,在此叩谢!