SpringMVC源码--控制器Handler到底是个什么?

     有些结论感觉是错的 整体看看就好 不过有些是对的 看个人理解吧

      相信看了前边的文章,心理总是会有一些困惑。控制器Handler到底是个什么呢?首先我们可以确定的是它是一个Object对象。其次,它允许是String类型,允许是Spring Bean,允许是HandlerExecutionChain。到底是什么,取决于处于哪个阶段。

     源码中第一次出现handler是在AbstractHandlerMapping类的getHandler()方法中,代码如下:


 
 
  1.   public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2.         Object handler = getHandlerInternal(request);
  3.          if (handler == null) {
  4.             handler = getDefaultHandler();
  5.         }
  6.          if (handler == null) {
  7.              return null;
  8.         }
  9.          // Bean name or resolved handler?
  10.          if (handler instanceof String) {
  11.             String handlerName = (String) handler;
  12.             handler = getApplicationContext().getBean(handlerName);
  13.         }
  14.          return getHandlerExecutionChain(handler, request);
  15.     }

   我们通过getHandlerInternal()方法来得到我们想要的handler。它有三处实现,分别是:

   第一个实现在AbstractHandlerMethodMapping类中,代码如下: 


 
 
  1.   protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  2.         //根据请求url得到handler的查找路径
  3.         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  4.         //根据handler的路径找到一个HandlerMethod
  5.         HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  6.          return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
  7.     }

   可以看到,返回值是HandlerMethod类型的。是不是有点看不懂了?没关系,我们看看HandlerMethod 类的构造方法:


 
 
  1.   public HandlerMethod(Object bean, Method method) {
  2.          this.bean = bean;
  3.          this.beanFactory = null;
  4.          this.method = method;
  5.          this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
  6.          this.parameters = initMethodParameters();
  7.     }

   嗯哼?所以,HandlerMethod 是一个包含了handler的Bean本身和请求方法的对象!也就是说,所谓的handler在这里,是指包含了我们请求的Controller类和Method方法的对象。如此,都说的通了。难怪DispatcherServlet类中可以用适配器来调用我们的Controller层方法!

我们再来看看handlerMethod.createWithResolvedBean() 方法是个啥,上代码:


 
 
  1. public HandlerMethod createWithResolvedBean() {
  2.         Object handler = this.bean;
  3.          if ( this.bean instanceof String) {
  4.             String beanName = (String) this.bean;
  5.             handler = this.beanFactory.getBean(beanName);
  6.         }
  7.          return new HandlerMethod( this, handler);
  8.     }


   熟悉不熟悉?惊喜不惊喜?可以比较一下AbstractHandlerMapping类的getHandler()方法中的代码和此处的代码,做了一件同样的事,将String类型的handler作为BeanName来得到对应的Bean对象。

 第一个实现在AbstractURLHandlerMapping类中,代码如下:


 
 
  1. protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
  2.         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  3.         Object handler = lookupHandler(lookupPath, request);
  4.          return handler;
  5. }
  6. protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
  7.          // Direct match?
  8.         Object handler = this.handlerMap.get(urlPath);
  9.          if (handler != null) {
  10.              // Bean name or resolved handler?
  11.              if (handler instanceof String) {
  12.                 String handlerName = (String) handler;
  13.                 handler = getApplicationContext().getBean(handlerName);
  14.             }
  15.             validateHandler(handler, request);
  16.              return buildPathExposingHandler(handler, urlPath, urlPath, null);
  17.         }
  18.  }
  19.  

  我们在前面的文章Handler的注册中提到过handlerMap这个东西,

  this.handlerMap.put(urlPath, resolvedHandler);
 
 

  到这里,就结束了。需要注意的是方法的最后调用了buildPathExposingHandler()方法,实现代码如下: 


 
 
  1. protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
  2.             String pathWithinMapping, Map<String, String> uriTemplateVariables) {
  3.         HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
  4.         chain.addInterceptor( new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
  5.          if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
  6.             chain.addInterceptor( new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
  7.         }
  8.          return chain;
  9. }

可以看出,最后返回了一个HandlerExecutionChain 类型的handler;

 第一个实现在EmptyHandlerMapping类中,代码如下:


 
 
  1. protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
  2.              return null;
  3.  }

这种情况下,返回值是空的,所以直接使用默认handler了。

 

    那么问题来了,handler到底是什么呢?它是对Controller的Bean本身和请求Method的包装。而HandlerExecutionChain 是handler的二次包装,将handler与拦截器链关联到了一起。然后,在DispatcherServlert中完成了拦截器链对handler的过滤。

   补充:一直在疑惑为什么只要被@Controller注解标注的Controller类就可以作为SpringMVC的请求处理类,它是怎么发挥作用的呢?这是因为@Controller注解继承了@Component注解,所以被@Controller注解标注的类会被Spring容器扫描并注册到容器中。至于真正发挥作用,就在于下面这段关键性的代码了:

        if (this.bean instanceof String) {
            String beanName = (String) this.bean;
            handler = this.beanFactory.getBean(beanName);
        }

  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">2</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/qq_28802119">
                    <img src="https://profile.csdnimg.cn/0/9/0/3_qq_28802119" class="avatar_pic" username="qq_28802119">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/2x/5.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/qq_28802119" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">小雨的光</a></span>
                                            </div>
                    <div class="text"><span>发布了119 篇原创文章</span> · <span>获赞 22</span> · <span>访问量 2万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=qq_28802119" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值