SpringMVC底层代码

这时我们就大致了解了,这个DispatcherServlet初始化的过程了,首先DispatcherServlet持有者一个以自己的Servlet名字命名的Ioc容器,也就是我们看到的WebApplicationContext对象,这个Ioc容器建立起来后,与Web容器相关的各种配置加载也都完成了。并且这个初始化的入口就是由最初的HttpServletBean的init方法触发的,因为这个HttpServletBean是HttpServlet的子类,接下来HttpServletBean的子类FrameworkServlet对Ioc容器进行了初始化操作,并且利用onRefresh方法回调了DispatcherServlet中的initStrategies方法,在这个方法里启动了整个SpringMVC框架了,我们继续往下面跟进看看。

//该属性默认为true

private boolean detectAllHandlerMappings = true; private void initHandlerMappings(ApplicationContext context) 
    {        this.handlerMappings = null;        //这里面的逻辑是从导入所有的HandlerMappingBean,这些Bean有可能存在与双亲容器中,也可能在DispathcerServlet持有的容器的,这里detectAllHandlerMappings默认为true,默认从所有容器中导入
            if(this.detectAllHandlerMappings) {
                        Map hm = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
                        if(!hm.isEmpty()) {
                        this.handlerMappings = new ArrayList(hm.values());                AnnotationAwareOrderComparator.sort(this.handlerMappings);
                                                                }
                       } else {
                       //否则通过直接通过名字从当前的IOC容器中通过getBean方法获取handlerMapping
                        try {
                       HandlerMapping hm1 = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                     this.handlerMappings = Collections.singletonList(hm1);
                    } catch (NoSuchBeanDefinitionException var3) {
;
                       }
                                                                                                                                                    }
//如果还是没有找到hadlerMapping就需要设定默认的handlerMappings了
                                                                                                                                                                    if(this.handlerMappings == null) {
                                                                                                                                                                                this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);            if(this.logger.isTraceEnabled()) {
                                                                                                                                                                                                this.logger.trace("No HandlerMappings declared for servlet \'" + this.getServletName() + "\': using default strategies from DispatcherServlet.properties");
                                                                                                                                                                                                            }
                                                                                                                                                                                                                    }
                                                                                                                                                                                                                         }

从上面的分析已经知道了当初始化完成的时候context中所有的handlerMapping都被加载了,并且它们都存放在hadlerMappings这么一个List中并且被排序了。我们看看HandlerMapping的设计及类的结构关系如下:

这里可以看到顶层的父接口就是HandlerMapping,进入这个类发现这个顶层接口定义了(一些常量以及一个getHandler方法)并且通过该方法会返回HandlerExecutionChain这么一个对象。

跟进这个HandlerExecutionChain这个类看看,这个类中有这么Interceptor链和一个handler这个两个关键的成员。说白了这个handler就是HTTP请求对应的那个Controller,并且这个Interceptor链也就是我们配置的各种拦截器,多个拦截器组成了拦截器链,通过拦截器链对我们handler进行一系列的增强。当然这个HandlerExecutionChain类还提供了一些维护这个拦截器链的API

这里主要关注的是RequestMappingInfoHandlerMapping、AbstractHandlerMethodMapping。从这张Diagrams图可以发现,这个AbstractHandlerMethodMapping实现了InitializingBean接口并且实现了afterPropertiesSet方法。

并且整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods方法主导的。为什么这么说呢,我们都知道SpringBean在创建bean的过程是先经过了bean的实例化、bean的属性填充、bean的初始化等步骤。

到这里终于清楚了为什么说整个初始化的工作是由AbstractHandlerMethodMapping的initHandlerMethods主导了,原因就是在这个类中Spring回调方法afterPropertiesSet里面又调用了initHandlerMethods方法。

接下来主要分析以下这个initHandlerMethods方法究竟干了什么,大体逻辑就是先获取应用中所有Object的bean的名字,然后遍历它循环获取这个beanName对应的beanType,判断这个bean是不是一个handler

并且从代码中我们可以知道判断一个Bean是不是一个Handler的逻辑就是判断这个Bean是否含有Controller注解或RequestMapping注解

首先看看这个selectMethods方法到底做了什么,从字面意思理解是按照规则来选取给定的类里面中方法。具体逻辑细化可以分为两步.

第一步:若这个targetType不是一个代理类,就获得它本身的类以及它的接口放入handlerTypes这么一个Set中去。

第二步:遍历这个handlerTypes,找到用户自己定义的方法并过滤出有requestMapping的方法,并将之塞入一个methodMap中
所以这下detectHandlerMethods里面上半部分在干什么就已经知道了:无非就是获取这个handler类里面用户自定义的方法中有requestMapping注解信息的方法,并将该方法作为key,requestMapping注解信息作为value存入一个名为methods的Map中去
这里不得不提到这个RequestMappingInfo这个类,这个类就是封装了requestMapping注解信息的这么一个类,有兴趣的可以自己去看看它的内部定义,这里就不详解了。

继续跟进这个getHandlerInternal方法,首先它根据这个request获取它的URI,接着通过uri获取对应的HandlerMethod对象最终返回了。

整个获取url并返回Handler的方式是使用了HandlerMethod来查找request的url

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值