springmvc-源码简析

 

首先来看Servlet的相关接口

javax.servlet.Servlet

 1 /**
 2  * A servlet is a small Java program that runs within a Web server.
 3  * Servlets receive and respond to requests from Web clients,
 4  * usually across HTTP, the HyperText Transfer Protocol. 
 5 **/
 6 //javax.servlet.Servlet接口
 7 public interface Servlet {
 8     //servlet容器会保证servlet实例化后开始服务前调用init方法
 9     public void init(ServletConfig config) throws ServletException;
10     
11     public ServletConfig getServletConfig();
12     
13     public void service(ServletRequest req, ServletResponse res)
14     throws ServletException, IOException;
15 
16     public String getServletInfo();
17     //servlet容器关闭时被调用,tomcat的shutdown.bat
18     public void destroy();
19 }
View Code

javax.servlet.http.HttpServlet

在使用原生servlet开发时,我们通常会继承javax.servlet.http.HttpServlet,包括SpringMVC中的DispatcherServlet也是继承了HttpServlet,并重写了doXxx方法。

 1 //javax.servlet.http.HttpServlet
 2 //HttpServlet实现了Servlet,重写的service方法只是做了类型强制转换,然后调用重载方法
 3 public void service(ServletRequest req, ServletResponse res)
 4     throws ServletException, IOException
 5 {
 6     HttpServletRequest  request;
 7     HttpServletResponse response;
 8     
 9     if (!(req instanceof HttpServletRequest &&
10             res instanceof HttpServletResponse)) {
11         throw new ServletException("non-HTTP request or response");
12     }
13 
14     request = (HttpServletRequest) req;
15     response = (HttpServletResponse) res;
16 
17     service(request, response);
18 }
View Code

 

 1 //service(ServletRequest req, ServletResponse res)的重载方法    
 2 protected void service(HttpServletRequest req, HttpServletResponse resp)
 3         throws ServletException, IOException
 4 {
 5     String method = req.getMethod();
 6 
 7     if (method.equals(METHOD_GET)) {
 8       doGet(req, resp);
 9     } else if (method.equals(METHOD_HEAD)) {
10       doHead(req, resp);
11     } else if (method.equals(METHOD_POST)) {
12       doPost(req, resp);
13     } else if (method.equals(METHOD_PUT)) {
14       doPut(req, resp);
15     } else if (method.equals(METHOD_DELETE)) {
16       doDelete(req, resp);
17     } else if (method.equals(METHOD_OPTIONS)) {
18       doOptions(req,resp);
19     } else if (method.equals(METHOD_TRACE)) {
20       doTrace(req,resp);
21     } else {
22       String errMsg = lStrings.getString("http.method_not_implemented");
23       Object[] errArgs = new Object[1];
24       errArgs[0] = method;
25       errMsg = MessageFormat.format(errMsg, errArgs);
26       resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
27     }
28 }
View Code

 

以上简单回顾了Servlet了相关接口,下面就来看SpringMVC。

我们配置SpringMVC时都会在web.xml中配置一个Servlet

 1 <servlet>
 2     <servlet-name>springMVC</servlet-name>
 3     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 4     <init-param>
 5       <param-name>contextConfigLocation</param-name>
 6       <param-value>classpath:spring-mvc.xml</param-value>
 7     </init-param>
 8     <load-on-startup>1</load-on-startup>
 9 </servlet>
10 <servlet-mapping>
11     <servlet-name>springMVC</servlet-name>
12     <url-pattern>/</url-pattern>
13 </servlet-mapping>

 

这个Servlet就是SpringMVC的请求入口,将该Servlet的url-pattern配置为"/"表示默认Servlet,即没有其他Servlet匹配时,匹配该Servlet,这与"/*"不同,后者会匹配所有url,这就会出现问题。Servlet容器内部forward到jsp时仍然被映射到该Servlet,最终DispatcherServlet会调用Servlet容器的defaultServlet处理资源,即将jsp当做静态资源来处理了。还会出现性能问题,一般js、css等静态资源不会放在WEB-INF下,而是放在webapp下,当设置为"/*"时,静态仍然会走DispatcherServlet,然后再找到defaultServlet,这势必是低效的。

DispatcherServlet

DispatcherServlet的核心逻辑在doDispatch

 1 //DispatcherServlet的doDispatcher,有删减
 2 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
 3 
 4     // Determine handler for the current request.
 5     //得到handler+interceptors
 6     HandlerExecutionChain mappedHandler = getHandler(processedRequest);
 7     
 8     // Determine handler adapter for the current request.
 9     HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
10 
11     if (!mappedHandler.applyPreHandle(processedRequest, response)) {
12         return;
13     }
14 
15     // Actually invoke the handler.
16     ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
17 
18     applyDefaultViewName(processedRequest, mv);
19     mappedHandler.applyPostHandle(processedRequest, response, mv);
20     //渲染
21     processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
22     
23 }

 

getHandler

 1 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 2     for (HandlerMapping hm : this.handlerMappings) {
 3         //HandlerExecutionChain中持有handler和interceptors
 4         HandlerExecutionChain handler = hm.getHandler(request);
 5         if (handler != null) {
 6             return handler;
 7         }
 8     }
 9     return null;
10 }

 

下面以以RequestMappingHandlerMapping为例来看hm.getHanlder

 1 //RequestMappingHandlerMapping的getHandler的主要逻辑,有删减
 2 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 3     
 4     Object handler = getHandlerInternal(request);
 5     if (handler == null) {
 6         handler = getDefaultHandler();
 7     }
 8     //handler+interceptors
 9     HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
10 
11     return executionChain;
12 }

 

 1 //AbstractHandlerMethodMapping的getHandlerInternal,有删减
 2 protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
 3     String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
 4     
 5     List<Match> matches = new ArrayList<Match>();
 6     //根据url得到mappings,mapping即org.springframework.web.servlet.mvc.method.RequestMappingInfo,就是我们在@RequestMapping中设置的条件
 7     List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
 8     if (directPathMatches != null) {
 9         addMatchingMappings(directPathMatches, matches, request);
10     }
11 
12 
13     if (!matches.isEmpty()) {
14         Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
15         //排序之后,首个元素就是最匹配的HandlerMethod
16         Collections.sort(matches, comparator);
17 
18         Match bestMatch = matches.get(0);
19 
20         handleMatch(bestMatch.mapping, lookupPath, request);
21         return bestMatch.handlerMethod;
22     }
23     else {
24         return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
25     }
26 }

 

 1 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
 2     HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
 3             (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
 4     //用于matching
 5     String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
 6     for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
 7         //<mvc:interceptor>
 8       //    <mvc:mapping path="/xxx/yyy" />
 9       //</mvc:interceptor>
10         if (interceptor instanceof MappedInterceptor) {
11             MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
12             if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
13                 chain.addInterceptor(mappedInterceptor.getInterceptor());
14             }
15         }
16         else {
17             chain.addInterceptor(interceptor);
18         }
19     }
20     return chain;
21 }

getHandlerAdapter

1 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
2     for (HandlerAdapter ha : this.handlerAdapters) {
3         if (ha.supports(handler)) {
4             return ha;
5         }
6     }
7 }

仍然以RequestMappingHandlerAdapter为例

1 //RequestMappingHandlerAdapter的supports
2 public final boolean supports(Object handler) {
3     //supportsInternal直接返回true
4     return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
5 }

为什么要handlerAdapter呢?handler有很多种实现,比如@Controller、AbstractController等,每一种实现的handler方法都不尽相同,@Controller是完全自定义的方法,AbstractController重写handleRequestInternal()即可,DispatcherServlet要如何统一调用这么丰富的入口呢?DispatcherServlet面对的必须是一个接口,通过这个接口又可以调用到具体的handler,最简单的方法就是让handler实现该接口,但这样势必在handler中参入了“杂质”。现在我们面对的是一系列handler、一个DispatcherServlet、一个DispatcherServlet调用的接口,handler不容易直接实现该接口,而DispatcherServlet又一定要使用该接口,那就只能找一个适配器,将handler适配到接口上了,这就是HandlerAdapter,也即适配器模式

applyPreHandle

 1 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
 2     HandlerInterceptor[] interceptors = getInterceptors();
 3     for (int i = 0; i < interceptors.length; i++) {
 4         HandlerInterceptor interceptor = interceptors[i];
 5         if (!interceptor.preHandle(request, response, this.handler)) {
 6             triggerAfterCompletion(request, response, null);
 7             return false;
 8         }
 9         //注意这里会修改interceptorIndex,triggerAfterCompletion和postHandle都是从interceptorIndex开始向0遍历
10         this.interceptorIndex = i;
11     }
12     return true;
13 }

triggerAfterCompletion

1 void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
2             throws Exception {
3     HandlerInterceptor[] interceptors = getInterceptors();
4     //从interceptorIndex开始
5     for (int i = this.interceptorIndex; i >= 0; i--) {
6         HandlerInterceptor interceptor = interceptors[i];
7         interceptor.afterCompletion(request, response, this.handler, ex);
8     }
9 }

applyPostHandle

1 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
2     HandlerInterceptor[] interceptors = getInterceptors();
3     //从interceptorIndex开始
4     for (int i = interceptors.length - 1; i >= 0; i--) {
5         HandlerInterceptor interceptor = interceptors[i];
6         interceptor.postHandle(request, response, this.handler, mv);
7     }
8 }

processDispatchResult

 1 private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
 2         HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
 3 
 4     boolean errorView = false;
 5 
 6     if (exception != null) {
 7         //@ExceptionHandler方法
 8         if (exception instanceof ModelAndViewDefiningException) {
 9             logger.debug("ModelAndViewDefiningException encountered", exception);
10             mv = ((ModelAndViewDefiningException) exception).getModelAndView();
11         }
12         //实现HandlerExceptionResolver
13         else {
14             Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
15             mv = processHandlerException(request, response, handler, exception);
16             errorView = (mv != null);
17         }
18     }
19     //不论是Exception还是正常处理,统一进行渲染
20     // Did the handler return a view to render?
21     if (mv != null && !mv.wasCleared()) {
22         render(mv, request, response);
23     }
24     //之前当preHandle返回false时不执行postHanlde、handle,直接调用triggerAfterCompletion并返回
25     if (mappedHandler != null) {
26         mappedHandler.triggerAfterCompletion(request, response, null);
27     }
28 }

 

handle

 1 //handle的核心方法,有删减
 2 protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
 3         HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 4 
 5     ServletWebRequest webRequest = new ServletWebRequest(request, response);
 6 
 7     WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
 8     ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
 9     
10     ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
11     //HandlerMethodArgumentResolver解析参数(将形参赋值),它将Request中的数据解析到handler的参数上,
12     invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
13     invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
14     //databinder的作用是将Request中的parameters绑定到特定对象实例上,属于参数解析的过程
15     invocableMethod.setDataBinderFactory(binderFactory);
16     invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
17 
18     ModelAndViewContainer mavContainer = new ModelAndViewContainer();
19     mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
20     /**
21      * Populate the model in the following order:
22      * <ol>
23      * <li>Retrieve "known" session attributes listed as {@code @SessionAttributes}.
24      * <li>Invoke {@code @ModelAttribute} methods
25      * <li>Find {@code @ModelAttribute} method arguments also listed as
26      * {@code @SessionAttributes} and ensure they're present in the model raising
27      * an exception if necessary.
28      * </ol>
29      * @param request the current request
30      * @param container a container with the model to be initialized
31      * @param handlerMethod the method for which the model is initialized
32      * @throws Exception may arise from {@code @ModelAttribute} methods
33      */
34      //initModel分3步初始化model:
35      //1从sessionAttributes获取@SessionAttributes中罗列的属性,
36      //2调用@ModelAttribute方法,
37      //3如果model中上不存在注有@ModelAttribute的形参的属性,则尝试从sessionAttributes中获取该属性
38     modelFactory.initModel(webRequest, mavContainer, invocableMethod);
39    //解析参数,然后反射调用函数
40     invocableMethod.invokeAndHandle(webRequest, mavContainer);
41 
42     return getModelAndView(mavContainer, modelFactory, webRequest);
43 }

 

在反射调用真正handle之前,会遍历函数的形参,通过HandlerMethodArgumentResolver对形参进行解析,得到实参。比如注解为@PathVariable的形参,PathVariableMethodArgumentResolver通过分析url来得到实参;注解为@RequestBody的形参,RequestResponseBodyMethodProcessor通过调用messageConverter来解析http请求的body;普通的javabean,ModelAttributeMethodProcessor会通过dataBinder进行数据绑定。

posted @ 2017-08-22 10:38  holoyong  阅读(181)  评论(0编辑  收藏  举报