Spring 源码解析之HandlerMapping源码解析(一)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

Spring 源码解析之HandlerMapping源码解析(一)

前言

这个是spring源码解析的第一篇,全文围绕着DispatcherServlet进行展开,Spring 的初始化基本都是通过DispatcherServlet进行初始化的,Spring boot除外,Spring boot是先初始化一个容器之后再初始化的DispatcherServlet,本文首先介绍Spring的HandlerMapping,本文的主要流程围绕着请求流程展开,而不是初始化流程,后续会按照流程的形式对源码进行解读,个人感觉这种方式比较容易理解。阅读源码的原因就是想了解Spring每个流程的实现,以及学习到更深层次的东西。

1.HandlerMapping功能分析

HandlerMapping是spring中最重要的一个类,主要功能就是为请求找到合适的处理器,现在Controller只是处理器的一种,目前我们自己公司自己实现了一套框架,前端js可以直接调用后端 soa service,忽略controller的存在,适合一些无用户状态的场景,比如说rest接口。

先来介绍下目前spring 已经提供的handlermapping

1.BeanNameUrlHandlerMapping

请求路径到bean name的映射

2.SimpleUrlHandlerMapping

最原始的spring使用方式,根struts差不多,通过配置请求路径对应处理的controller类,如下面例子

    <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
    <props>
        <prop key="/listCourses.go">listCoursesController</prop>
        <prop key="/login.go">loginController</prop>
    <props>
    <property>
    <bean>

3.ControllerBeanNameHandlerMapping

This is similar to BeanNameUrlHandlerMapping but doesn’t expect bean names to follow the URL convention: It turns plain bean names into URLs by prepending a slash and optionally applying a specified prefix and/or suffix. However, it only does so for well-known controller types, as listed above (analogous to ControllerClassNameHandlerMapping).

4.ControllerClassNameHandlerMapping

这个主要是类名映射,看看下面就知道了
* WelcomeController -> /welcome*
* HomeController -> /home*
这种方式通常搭配着MultiActionController ,比如/abc/to_add.do 这个表示调用AbcController.java下的to_add的方法。前提是AbcController.java继承MultiActionController

5.RequestMappingHandlerMapping(3.2之前是使用DefaultAnnotationHandlerMapping 这个去处理,但是后来弃用了)

这个就是现在默认的请求匹配方式,通过@RequestMapping 注解来决定调用方法和具体的类,也是最常用的一种。

DispatcherServlet初始化的时候会调用initHandlerMappings()进行初始化

    protected void initStrategies(ApplicationContext context) {
            initMultipartResolver(context);
            initLocaleResolver(context);
            initThemeResolver(context);
            initHandlerMappings(context);
            initHandlerAdapters(context);
            initHandlerExceptionResolvers(context);
            initRequestToViewNameTranslator(context);
            initViewResolvers(context);
            initFlashMapManager(context);
        }
      //初始化handlermapping
      private void initHandlerMappings(ApplicationContext context) {
            this.handlerMappings = null;
            //判断是否默认添加所有的HandlerMappings,初始值是默认添加的
            if (this.detectAllHandlerMappings) {
                // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
                Map<String, HandlerMapping> matchingBeans =
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
                if (!matchingBeans.isEmpty()) {
                    this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                    // We keep HandlerMappings in sorted order.
                    //通过@order注解去排序
                    AnnotationAwareOrderComparator.sort(this.handlerMappings);
                }
            }
            //如果不是默认添加所有的,那么就去context中找一个声明的bean
            else {
                try {
                    HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                    this.handlerMappings = Collections.singletonList(hm);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Ignore, we'll add a default HandlerMapping later.
                }
            }

            // Ensure we have at least one HandlerMapping, by registering
            // a default HandlerMapping if no other mappings are found.
            //如果上面两步没有找到可以使用的handlerMapping,那么就采用默认的handlerMapping
            //默认的HandlerMapping都定义在了DispatcherServlet.properties中,大致定义了如下两个
            //org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
        //org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
            if (this.handlerMappings == null) {
                this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
                }
            }
        }

下面是初始化之后的一个状态,我这边使用的是spring boot启动,大致会初始化10个handlermapping,如下图所示:

20191102100621\_1.png

下图可以看到,默认的RequestMappingHandlerMapping已经把所有路径映射进去,相关的spring拦截器也放到了RequestMappingHandlerMapping中,由此说来,拦截器其实是跟RequestMappingHandlerMapping进行关联的。

20191102100621\_2.png

2. HandlerMapping流程分析

HandlerMapping流程需要弄清楚几个类的定义:

1. HandlerExecutionChain

(Handler execution chain, consisting of handler object and any handler interceptors. Returned by HandlerMapping’s)根据英文的翻译来说HandlerExecutionChain是 handler的执行链,由一些handler object 和 handler interceptors组成,这个里面包含了interceptor的所有执行,包括这个请求是否通过preHandle,大致逻辑如下


             boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
                 //获取所有拦截器进行遍历
                HandlerInterceptor[] interceptors = getInterceptors();
                if (!ObjectUtils.isEmpty(interceptors)) {
                    for (int i = 0; i < interceptors.length; i++) {
                        HandlerInterceptor interceptor = interceptors[i];
                        //判断拦截器是否可以继续执行
                        if (!interceptor.preHandle(request, response, this.handler)) {
                            triggerAfterCompletion(request, response, null);
                            return false;
                        }
                        this.interceptorIndex = i;
                    }
                }
                return true;
            }
2. HandlerAdapter

HandlerAdapter 这个是spring的核心功能,所有的请求对应Controller方法都是通过HandlerAdapter 大该作用就是进行方法映射和调用并且返回结果,对应spring中正常用法实现类是HttpRequestHandlerAdapter,一般基本的http请求都是通过这个进行处理的。

请求处理流程分析

先来看看这段代码,spring的核心。所有请求调用都是通过这里进行的,可以说是关键路径


    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 {
                    //优先判断一下是不是文件上传的request
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
                    //获取到相应处理该request的HandlerExecutionChain,
                    //静态资源一般都是由ResourceHttpRequestHandler进行处理的
                    // Determine handler for the current request.
                    mappedHandler = getHandler(processedRequest);
                    //如果没有找到相应的handler,这里就是大家经常从日志里面看到的这段英文No mapping found for HTTP request with URI
                    //这个地方没有找到相应的处理handler有两种处理方式,一种(默认)返回404的状态码,一种是直接抛出异常,第二种方式需要设置初始化参数的
                    //throwExceptionIfNoHandlerFound 这个参数设置成ture即可
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
                    //通过handler找到对应处理的handlerAdapter
                    // Determine handler adapter for the current request.
                    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;
                        }
                    }
                    //执行HandlerExecutionChain所有Interceptor中的preHandle方法,一旦有一个返回了false那么请求就不进行继续处理
                    //这也是为什么preHandle 返回了false就可以拦截用户继续执行了
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //实际调用的handler,如果是http请求会调用相应的HandlerMethod 这里里面包含了具体的方法,通过反射调用,如果有返回的视图,那么ModelAndView会返回相应的视图对象,如果只是普通请求或者json请求会返回null
                    // Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    //这块会校验是否添加了视图,如果没有视图就会添加一个默认的视图,通过url的规则来拼凑
                    applyDefaultViewName(processedRequest, mv);
                    //这块逻辑是执行HandlerExecutionChain所有Interceptor中的postHandle方法,从这块代码看来,postHandle的执行时机是在执行完方法后没有把响应写入到response中执行的
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                //处理请求,把参数都写入到request里面
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            }
            catch (Error err) {
                triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
            }
            finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    // Instead of postHandle and afterCompletion
                    if (mappedHandler != null) {
                        //最后调用HandlerExecutionChain所有Interceptor中的postHandle方法
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                }
                else {
                    // Clean up any resources used by a multipart request.
                    if (multipartRequestParsed) {
                        cleanupMultipart(processedRequest);
                    }
                }
            }
        }

下图是上述代码的一个大致流程

20191102100621\_3.png

总结

遗留问题如下:

  1. getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping
  2. getHandlerAdapter(mappedHandler.getHandler());如果取到对应的HandlerAdapter

这个是解析的第一篇,如果在流程活着代码描述上不准确的,望大家多多指教


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring 源码解析之HandlerMapping源码解析(一)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏