• 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进行数据绑定。

  • 相关阅读:
    网络编程 Linux IP地址、子网掩码、网关设置和获取
    RFC 3021 Using 31Bit Prefixes on IPv4 PointtoPoint Links
    MySQL SSL 加密连接浅析
    四两拨千斤 —— Ubuntu kernel eBPF 0day分析[腾讯安全应急响应中心20180408]
    supervisor中group与program同时存在,部分program在gunicorn中不启动
    阅读习惯
    网络对抗技术Exp2后门原理与实践
    攻击树测试
    密码常识测试
    网络对抗技术Exp1逆向破解实验
  • 原文地址:https://www.cnblogs.com/holoyong/p/7384307.html
Copyright © 2020-2023  润新知