SpringMVC:(二)根据请求查找对应的Controller方法的流程

前言:

   在这之前我们已经建立请求和Controller方法的映射集合,接下来我们就要去取出映射关系里获取请求的逻辑实例。

 根据请求查找对应的Controller方法的流程主要发生在DispatcherServlet类的doDispatch()方法。该方法的调用时机是当我们访问路径:http://localhost:8080/springmvcdemo/headline/open 的时候

观察下面的流程图我们可以看到

(1)会去访问到DispatcherServlet的父类FrameworkServlet的service()方法

(2)然后会根据请求选择doGet()或者doPost()方法

(3)然后父类会去调用到子类DispatcherServlet的doService()方法去处理逻辑

(4)DispatcherServlet的doService()方法会去调用doDispatch()去派遣给Controller执行   =>  (根据请求查找对应的Controller方法)就是在该方法中调用了getHandler()去获取的


这里我们重新回到RequestMappingHandlerMapping类中。

我们观察其类图:

通过观察类图我们发现该类还实现了HandlerMapping接口,该接口就一个getHanndler()方法。该方法只需要给其传递HttpServletRequest参数即可返回HandlerExecutionChain对象

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

类图上显示HandlerMapping接口的主要实现类为:AbstractHandlerMapping类。

接下来我们跟进到AbstractHandlerMapping类的getHanndler()方法。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获取handler的具体逻辑,留给子类实现
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            //如果获取到的handler为null则采用默认的handler,即属性defaultHandler
            handler = getDefaultHandler();
        }
        if (handler == null) {
            //如果连DefaultHandler也为空,则直接返回空
            return null;
        }
        // Bean name or resolved handler?
        //如果handler是beanName,从容器里获取对应的bean
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        //根据handler和request获取处理器链HandlerExecutionChain
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//获取到执行器链
   
     //下面的代码与主要流程无关(略) if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {logger.debug("Mapped to " + executionChain.getHandler());} if (hasCorsConfigurationSource(handler)) { CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); config = (config != null ? config.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain;//返回执行器链 }

(1)调用子类的getHandlerInternal()方法去获取handler的具体逻辑(AbstractHandlerMethodMapping.getHandlerInternal()方法)

  (A)获取到Request(请求)中的URL(用来匹配handler)

    (B)调用lookupHandlerMethod()方法,根据路径寻找Handler,并封装成HandlerMethod

      (a)尝试从先前映射建立的时候存入的urlLookup中查找映射

      (b)如果匹配到了,检查其他属性是否符合要求,如请求方法,参数,hander等 (没有直接匹配到,则遍历所有的处理方法进行通配符匹配)

      (c)如果方法有多个匹配,不同的通配符等,则排序选择出最合适的一个

      (d)如果有多个匹配的,会找到第二个最合适的进行比较。

      (e)给请求(request)设置上属性参数

      (f)返回匹配的URL的处理的方法

    (C)根据handlerMethod中的bean来实例化Handler,并添加进HandlerMethod

(2)如果获取到的handler为null则采用默认的handler,即属性defaultHandler

(3)如果连DefaultHandler也为空,则直接返回空

(4)如果上面获取到的处理方法(handler)是实现了String接口,说明其只是一个beanName,此时我们要去容器中获取到真正对应的Bean

(5)根据处理方法(handler)和请求(request)获取处理器链(HandlerExecutionChain)

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        //判断handler是不是执行器链,如果不是则创建一个执行器链
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
        //包装拦截器
        /*可以去做一些请求的时候业余上对用户信息的拦截
            <mvc:interceptor>
                <mvc:mapping path="/shopadmin/**" />
                    <bean id="ShopInterceptor" class="com.imooc.o2o.interceptor.shopadmin.ShopLoginInterceptor" />
            </mvc:interceptor>
         */
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;//将包装好的执行器链返回
}

  (A)创建获取到执行器链(判断传入的handler(处理方法)是不是执行器链,如果不是则创建一个执行器链,如果是则强转为执行器链)

  (B)对获取到的执行器链进行包装拦截器(将配置好的拦截器for循环遍历然后筛选path,如果符合当前这个执行器链,则对其进行包装)

(6)无关逻辑(略)

(7)返回处理器链 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kerry_x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值