Spring源码学习笔记

Posted DarkFuture

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码学习笔记相关的知识,希望对你有一定的参考价值。

Spring源码学习笔记(三)

  前言----

       最近花了些时间看了《Spring源码深度解析》这本书,算是入门了Spring的源码吧。打算写下系列文章,回忆一下书的内容,总结代码的运行流程。推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的《Spring源码深度解析》这本书,会是个很好的入门。

 


 DispatcherServlet 实现核心功能

    和普通的 Servelt 类一样, DispatcherServlet 中的 doGet()doPost() 方法是实现其核心逻辑的方法, 在其父类 FrameworkServlet 中有该函数的实现。

1     protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2         this.processRequest(request, response);
3     }
4 
5     protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
6         this.processRequest(request, response);
7     }

    实现逻辑全部交给 processRequest() 方法, 继续跟踪~~~~

 1     protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         //第一步:  记录时间
 3         long startTime = System.currentTimeMillis();
 4         Throwable failureCause = null;
 5         //第二步:  记录当前线程的 LocaleContext 以及 RequestAttributes
 6         LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
 7         //第三步:  根据当前的 request 生成 LocaleContext 和 RequestAttributes
 8         LocaleContext localeContext = this.buildLocaleContext(request);
 9         RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
10         ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
11         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
12         asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
13         this.initContextHolders(request, localeContext, requestAttributes);
14 
15         try {
16             //第四步:  核心 doService()  方法 
17             this.doService(request, response);
18         } catch (ServletException var17) {
19             failureCause = var17;
20             throw var17;
21         } finally {
22             //第五步:  恢复 LocaleContext 以及 RequestAttributes
23             this.resetContextHolders(request, previousLocaleContext, previousAttributes);
24             if(requestAttributes != null) {
25                 requestAttributes.requestCompleted();
26             }
27             //第六步:  无论成功失败, 发布事件
28             this.publishRequestHandledEvent(request, startTime, (Throwable)failureCause);
29         }
30 
31     }

 

    在 processRequest() 方法中, 操作了 LocaleContext 和 RequestAttributes 外, 并没做什么, 核心逻辑在 doService() 方法中。 欲知后事, 烧香倒酒~~·

 1     protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
 2         
 3         Map<String, Object> attributesSnapshot = null;
 4         if(WebUtils.isIncludeRequest(request)) {
 5             this.logger.debug("Taking snapshot of request attributes before include");
 6             attributesSnapshot = new HashMap();
 7             //第一步: 生成迭代器,为当前的 request 的属性做快照
 8             Enumeration attrNames = request.getAttributeNames();
 9 
10             label113:
11             while(true) {
12                 String attrName;
13                 do {
14                     if(!attrNames.hasMoreElements()) {
15                         break label113;
16                     }
17 
18                     attrName = (String)attrNames.nextElement();
19                 } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
20 
21                 attributesSnapshot.put(attrName, request.getAttribute(attrName));
22             }
23         }
24 
25         //第二步:  给当前 Request 设置 已获取到的属性 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
26         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
27         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
28         request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
29         FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
30         if(inputFlashMap != null) {
31             request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
32         }
33 
34         request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
35         request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
36 
37         try {
38             //第三步:  准备工作后的真正逻辑处理
39             this.doDispatch(request, response);
40         } finally {
41             if(WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
42                 return;
43             }
44             //第四步:  从快照当中恢复属性
45             if(attributesSnapshot != null) {
46                 this.restoreAttributesAfterInclude(request, attributesSnapshot);
47             }
48 
49         }
50 
51     }

 

 

    一步一步似爪牙, 是魔鬼的步伐, 是。。。。。  这个 doDispatch() 方法真正进入了核心  <( ̄︶ ̄)↗[GO!]

 1     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
 2         HttpServletRequest processedRequest = request;
 3         HandlerExecutionChain mappedHandler = null;
 4         boolean multipartRequestParsed = false;
 5         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 6 
 7         try {
 8             try {
 9                 ModelAndView mv = null;
10                 Exception dispatchException = null;
11 
12                 try {
13                     //第一步:  检测 MultipartContent 类型的 request
14                     processedRequest = this.checkMultipart(request);
15                     multipartRequestParsed = processedRequest != request;
16                     //第二步:  根据当前的 request 获取对应的 handler
17                     mappedHandler = this.getHandler(processedRequest);
18                     if(mappedHandler == null || mappedHandler.getHandler() == null) {
19                         //第三步:  没有 对应的 handler 则报异常
20                         this.noHandlerFound(processedRequest, response);
21                         return;
22                     }
23                     //第四步:  根据 handler 获取对应的 handlerAdapter
24                     HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
25                     //第五步:  这里是对 http 的Last-Modified 头的处理, 相当于缓存策略
26                     String method = request.getMethod();
27                     boolean isGet = "GET".equals(method);
28                     if(isGet || "HEAD".equals(method)) {
29                         long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
30                         if(this.logger.isDebugEnabled()) {
31                             String requestUri = urlPathHelper.getRequestUri(request);
32                             this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
33                         }
34 
35                         if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
36                             return;
37                         }
38                     }
39                     //第六步:  调用拦截器的 preHandler 方法
40                     if(!mappedHandler.applyPreHandle(processedRequest, response)) {
41                         return;
42                     }
43 
44                     try {
45                         //第七步:  调用 HandlerAdapter 的方法, 返回视图
46                         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
47                     } finally {
48                         if(asyncManager.isConcurrentHandlingStarted()) {
49                             return;
50                         }
51 
52                     }
53 
54                     this.applyDefaultViewName(request, mv);
55                     //第八步:  调用拦截器的 postHandler 方法
56                     mappedHandler.applyPostHandle(processedRequest, response, mv);
57                 } catch (Exception var28) {
58                     dispatchException = var28;
59                 }
60                 //第九步:  进行返回视图的跳转  以及  激活触发器
61                 this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
62             } catch (Exception var29) {
63                 this.triggerAfterCompletion(processedRequest, response, mappedHandler, var29);
64             } catch (Error var30) {
65                 this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var30);
66             }
67 
68         } finally {
69             if(asyncManager.isConcurrentHandlingStarted()) {
70                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
71                 return;
72             } else {
73                 if(multipartRequestParsed) {
74                     this.cleanupMultipart(processedRequest);
75                 }
76 
77             }
78         }
79     }

 

    复杂的逻辑, 分成一个个步骤, 接下来详解  doDispatch()  方法的每个步骤。     另开新篇~~~~ ( ﹁ ﹁ ) ~→

 


    doDispatch( HttpServletRequest request, HttpServletResponse response ) 


 

 

    一, 检测 MutipartContent 类型的 request

 1     protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
 2         //第一步:  判断类型
 3         if(this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
 4             if(!(request instanceof MultipartHttpServletRequest)) {
 5                 //第二步:  调用方法
 6                 return this.multipartResolver.resolveMultipart(request);
 7             }
 8 
 9             this.logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, this typically results from an additional MultipartFilter in web.xml");
10         }
11         //第三步: 直接返回
12         return request;
13     }

 

    二, 根据 Request 获取 Handler

 1     protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 2         //第一步:  遍历所有的 HandlerMapping
 3         Iterator var2 = this.handlerMappings.iterator();
 4 
 5         HandlerExecutionChain handler;
 6         do {
 7             if(!var2.hasNext()) {
 8                 return null;
 9             }
10           
11             HandlerMapping hm = (HandlerMapping)var2.next();
12             if(this.logger.isTraceEnabled()) {
13                 this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");
14             }
15             //第二步:  调用 HandlerMapping 的方法
16             handler = hm.getHandler(request);
17         } while(handler == null);
18 
19         return handler;
20     }

 

    在  getHandler() 方法中, 第二步调用  HandlerMapping 的 getHandler() 方法, 其实现是在父类 AbstractHandlerMapping 中

    

    AbstractHandlerMapping 的 getHandler()  实现 : 

 1     public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 2         //第一步:  根据 request 获取对应的 handler
 3         Object handler = this.getHandlerInternal(request);
 4         if(handler == null) {
 5             //第二步:  使用默认的 handler
 6             handler = this.getDefaultHandler();
 7         }
 8 
 9         if(handler == null) {
10             return null;
11         } else {
12             if(handler instanceof String) {
13                 //第三步:  若为 String 类型, 实例化它
14                 String handlerName = (String)handler;
15                 handler = this.getApplicationContext().getBean(handlerName);
16             }
17             //第四步:  封装类型
18             return this.getHandlerExecutionChain(handler, request);
19         }
20     } 

 

    getHandler()  第一步中的 getHandlerInternal()  方法,  其实现是在 AbstractUrlHandlerMapping 类中:

 1    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
 2         //第一步:  截取 url 的有效路径
 3         String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
 4         //第二步:  根据路径获取 handler
 5         Object handler = this.lookupHandler(lookupPath, request);
 6         if(handler == null) {
 7             Object rawHandler = null;
 8             //第三步:  路径为 “/” 的情况
 9             if("/".equals(lookupPath)) {
10                 rawHandler = this.getRootHandler();
11             }
12             //第四步:  路径为 null 的情况, 使用默认 handler
13             if(rawHandler == null) {
14                 rawHandler = this.getDefaultHandler();
15             }
16 
17             if(rawHandler != null) {
18                 if(rawHandler instanceof String) {
19                     //第五步:  根据 name 获取对应的 bean
20                     String handlerName = (String)rawHandler;
21                     rawHandler = this.getApplicationContext().getBean(handlerName);
22                 }
23                 //第六步:  模板方法 (往后看)
24                 this.validateHandler(rawHandler, request);
25                 handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
26             }
27         }
28 
29         return handler;
30     }

 

    绝望的感觉, 对方不想和你说话,并又双叒叕向你扔了一大堆代码。。。  (ノಠ益ಠ)ノ彡┻━┻

    在 getHandlerInternal() 方法中, 第二步 lookupHandler() 的实现:

 1     protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
 2         Object handler = this.handlerMap.get(urlPath);
 3         //第一步:  缓存 handlerMap 中存在的情况
 4         if(handler != null) {
 5             if(handler instanceof String) {
 6                 String handlerName = (String)handler;
 7                 handler = this.getApplicationContext().getBean(handlerName);
 8             }
 9 
10             this.validateHandler(handler, request);
11             return this.buildPathExposingHandler(handler, urlPath, urlPath, (Map)null);
12         } else {
13             //第二步:  同配符匹配的情况
14             List<String> matchingPatterns = new ArrayList();
15             Iterator var5 = this.handlerMap.keySet().iterator();
16    
17             while(var5.hasNext()) {
18                 String registeredPattern = (String)var5.next();
19                 //第三步:  添加所有的要匹配的 Handler
20                 if(this.getPathMatcher().match(registeredPattern, urlPath)) {
21                     matchingPatterns.add(registeredPattern);
22                 }
23             }
24 
25             String bestPatternMatch = null;
26             Comparator<String> patternComparator = this.getPathMatcher().getPatternComparator(urlPath);
27             if(!matchingPatterns.isEmpty()) {
28                 //第四步:  根据 Comparator 排序所有的 Handler
29                 Collections.sort(matchingPatterns, patternComparator);
30                 if(this.logger.isDebugEnabled()) {
31                     this.logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
32                 }
33                 //第五步:  获取匹配的 Handler
34                 bestPatternMatch = (String)matchingPatterns.get(0);
35             }
36             
37             if(bestPatternMatch != null) {
38                 handler = this.handlerMap.get(bestPatternMatch);
39                 String pathWithinMapping;
40                 //第六步:  若是 String 类型, 则实例化
41                 if(handler instanceof String) {
42                     pathWithinMapping = (String)handler;
43                     handler = this.getApplicationContext().getBean(pathWithinMapping);
44                 }
45 
46                 this.validateHandler(handler, request);
47                 pathWithinMapping = this.getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
48                 //第七步:  若存在多个 最佳匹配, 在这些匹配中选出正确的 URI template variables
49                 Map<String, String> uriTemplateVariables = new LinkedHashMap();
50                 Iterator var9 = matchingPatterns.iterator();
51 
52                 while(var9.hasNext()) {
53                     String matchingPattern = (String)var9.next();
54                     if(patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
55                         Map<String, String> vars = this.getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
56                         Map<String, String> decodedVars = this.getUrlPathHelper().decodePathVariables(request, vars);
57                         uriTemplateVariables.putAll(decodedVars);
58                     }
59                 }
60                 //第八步: 封装
61                 return this.buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
62             } else {
63                 return null;
64             }
65         }
66     }

 

    其实在  lookupHandler() 方法当中, 只是一个 if-else 语句判断了 是直接匹配的情况 还是  同配符匹配的情况,最后把获取的 handler 封装成 HandlerExecutionChain 类。

 1     protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, String pathWithinMapping, Map<String, String> uriTemplateVariables) {
 2         //第一步:   封装成 HandlerExecutionChain 类型 
 3         HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
 4         //第二步:   为 chain 添加两个拦截器
 5         chain.addInterceptor(new AbstractUrlHandlerMapping.PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
 6         if(!CollectionUtils.isEmpty(uriTemplateVariables)) {
 7             chain.addInterceptor(new AbstractUrlHandlerMapping.UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
 8         }
 9 
10         return chain;
11     }

 

    在 getHandler() 方法中,第四步封装类型  getHandlerExecutionChain() 方法的实现:

 1     protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
 2         HandlerExecutionChain chain = handler instanceof HandlerExecutionChain?(HandlerExecutionChain)handler:new HandlerExecutionChain(handler);
 3         chain.addInterceptors(this.getAdaptedInterceptors());
 4         String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
 5         Iterator var5 = this.mappedInterceptors.iterator();
 6         //第一步:  封装过程, 就是为 chain 添加拦截器
 7         while(var5.hasNext()) {
 8             MappedInterceptor mappedInterceptor = (MappedInterceptor)var5.next();
 9             if(mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
10                 chain.addInterceptor(mappe

以上是关于Spring源码学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码学习笔记

Spring源码学习笔记

Spring源码学习笔记

Spring源码学习笔记1

spring学习笔记源码剖析

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段