文档章节

3 HandlerMapping 组件源码分析

java_sheng
 java_sheng
发布于 2017/08/30 20:41
字数 902
阅读 4
收藏 0


AbstractHandlerMapping 抽象类

主要是通过request找到handler 和 interceptors

继承了WebApplicationObjectSupport

    @Override
    protected void initApplicationContext() throws BeansException {
        //模板方法 暂时还没用
        extendInterceptors(this.interceptors);
        //从spring的容器中获取MappedInterceptor的类型放入集合中
        detectMappedInterceptors(this.adaptedInterceptors);
        //初始化拦截器
        initInterceptors();
    }

    //保存我们自定义的拦截器 
    //然后放到对应的adaptedInterceptors和mappedInterceptors
    interceptors
    //此类拦截器不需要匹配
    adaptedInterceptors
    //此类的拦截器需要和url进行匹配,
    //匹配成功后放入集合
    mappedInterceptors
    
----------------------------------------------------------------------
@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //模板方法 子类覆盖
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            //如果没有 就找默认的handler
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // string类型的 从容器中查找
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        
        //添加相应的拦截器
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        //这个是request是不是跨域的  具体也没用过这个
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }    
    
------------------------------------------------------------------------------------------    
第一种类型的 HandlerMapping

根据url查找handler的抽象类


AbstractUrlHandlerMapping

@Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        //根据request查找到 handler对应的url
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        //从map集合中找到lookupPath所对应的handler
        Object handler = lookupHandler(lookupPath, request);
        if (handler == null) {
            // We need to care for the default handler directly, since we need to
            // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
            Object rawHandler = null;
            if ("/".equals(lookupPath)) {
                //跟路径的handler
                rawHandler = getRootHandler();
            }
            if (rawHandler == null) {
                rawHandler = getDefaultHandler();
            }
            if (rawHandler != null) {
                // Bean name or resolved handler?
                if (rawHandler instanceof String) {
                    String handlerName = (String) rawHandler;
                    rawHandler = getApplicationContext().getBean(handlerName);
                }
                //模板方法 暂时没用
                validateHandler(rawHandler, request);
                //添加相应的拦截器
                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
            }
        }
        if (handler != null && logger.isDebugEnabled()) {
            logger.debug("Mapping [" + lookupPath + "] to " + handler);
        }
        else if (handler == null && logger.isTraceEnabled()) {
            logger.trace("No handler mapping found for [" + lookupPath + "]");
        }
        return handler;
    }
    
    
还有一个重要的方法是registerHandler 

//主要是通过子类handlerMap添加handler
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
        Object resolvedHandler = handler;

        // 判断是不是懒加载的
        if (!this.lazyInitHandlers && handler instanceof String) {
            String handlerName = (String) handler;
            if (getApplicationContext().isSingleton(handlerName)) {
                resolvedHandler = getApplicationContext().getBean(handlerName);
            }
        }

        Object mappedHandler = this.handlerMap.get(urlPath);
        if (mappedHandler != null) {
            //如果取出来的hander和resolvedHandler 不相同 就是有问题的
            if (mappedHandler != resolvedHandler) {
                throw new IllegalStateException(
                        "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                        "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
            }
        }
        else {
            if (urlPath.equals("/")) {
                if (logger.isInfoEnabled()) {
                    logger.info("Root mapping to " + getHandlerDescription(handler));
                }
                //跟路径的handler
                setRootHandler(resolvedHandler);
            }
            else if (urlPath.equals("/*")) {
                if (logger.isInfoEnabled()) {
                    logger.info("Default mapping to " + getHandlerDescription(handler));
                }
                //默认的handler
                setDefaultHandler(resolvedHandler);
            }
            else {
                this.handlerMap.put(urlPath, resolvedHandler);
                if (logger.isInfoEnabled()) {
                    logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
                }
            }
        }
    }    
    
    
-----------------------------------------------------------------------------------------
AbstractUrlHandlerMapping 下面有2个子类

SimpleUrlHandlerMapping     把url和handler的对应关系 注册到父类中

    @Override
    //重写父类的方法 把 urlmap 注册到父类中
    public void initApplicationContext() throws BeansException {
        super.initApplicationContext();
        registerHandlers(this.urlMap);
    }
    
    
AbstractDetectingUrlHandlerMapping 把bean拿出来 按照规则 注册到父类中

protected void detectHandlers() throws BeansException {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
        }
        //获取容器中所有的bean
        String[] beanNames = (this.detectHandlersInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));

        // Take any bean name that we can determine URLs for.
        for (String beanName : beanNames) {
            // 模板方法 具体的url规则由子类确定
            String[] urls = determineUrlsForHandler(beanName);
            if (!ObjectUtils.isEmpty(urls)) {
                //注册到父类中
                registerHandler(urls, beanName);
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
                }
            }
        }
    }


----------------------------------------------------------------------------------------------------------
第二种类型的 HandlerMapping

AbstractHandlerMethodMapping 将method作为handler来用
这也是我们经常使用的 @RequestMapping 注解

这个抽象类也是继承了AbstractHandlerMapping
重写父类getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //根据request查找到url
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //获取读锁 这个地方为什么要上锁 欢迎指导
        this.mappingRegistry.acquireReadLock();
        try {
            //获取具体的method
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }
    
------------------------------------------------------------------------------------------    
    
RequestMappingInfoHandlerMapping

他重写了父类的很多方法
    @Override
    protected boolean isHandler(Class<?> beanType) {
        //判断方法是否有 注解  
        return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
                (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
    }

核心的方法还是在AbstractHandlerMethodMapping中


 

© 著作权归作者所有

共有 人打赏支持
java_sheng
粉丝 0
博文 5
码字总数 3376
作品 0
浦东
后端工程师
私信 提问
SpringMVC源码系列:九大组件小记

前面几篇文章都是针对于SpringMVC中的具体组件进行源码分析的;本文主要用于补充记录一下关于SpringMVC中九大组件的学习。这个会牵扯出除之前的几篇之外的其他一些基础组件。 之前简单的有介...

glmapper
10/28
0
0
自己手写一个Spring MVC框架

想要了解Spring MVC框架的原理,探究框架是如何设计的,不错的学习方式是阅读源码,然后自己手写一个框架。本文带领大家简化的手写一个Spring MVC框架。 Spring框架对于Java后端程序员来说再...

技术小能手
08/01
0
0
SpringMVC源码解析(四)——请求处理

前言 这一篇,将着手介绍一次请求的处理。用到了 HandlerMapping、HandlerAdapter 知识,如果遇到不是太了解,可以回顾下。 源码分析 其实 DispatcherServlet 也只是 Servlet 的一个实现,只...

MarvelCode
07/05
0
0
Spring 源码分析(四) ——MVC(五)初始化阶段

DispatcherServlet 的初始化 Spring MVC 是基于 Servlet 功能实现的,通过实现 Servlet 接口的 DispatcherServlet 来封装其核心功能实现,通过将请求分派给处理程序,同时带有可配置的处理程...

水门-kay
2016/04/02
1K
0
【原创】遨游springmvc之HandlerMapping

1.前言 之前我们springmvc原理篇里已经介绍过,从springmvc核心处理器DispatcherServlet派遣请求的时候,首先会将请求包装,这就是我们这边介绍的HandlerMapping 在springmvc源码介绍中我们知...

开源中国首席脑科主任
2016/07/24
113
0

没有更多内容

加载失败,请刷新页面

加载更多

关于ElasticSearch的使用过程遇到的问题

由于作者从官网下载了ES5.6.10的安装包,解压之后就开始运行ES,前面一切正常。 后面某个查询条件失效。 解决: 1.先试了把单个查询条件撤离出来,当成一个Test来跑,发现还是获取不到值,表...

DoLo-lty
10分钟前
0
0
sed 替换文本内得路径字符等等

1. 句子 sed -i 's%/opt/apache-maven-3.5.3/conf/settings.xml%/data/opt/apache-maven-3.5.3/conf/settings.xml%g' ./*/config.xml 2. 解释 sed linux 一个文件流式处理的工具 2.1 -i 在当......

Aruforce
11分钟前
0
0
mysql_索引

索引类型 哈希表 有序数组 搜索树 MySQL索引 B-树 B+树 innodb的索引 索引维护 关于自增主键的使用 参考 极客时间《mysql实战45讲》

grace_233
11分钟前
0
0
“入乡随俗,服务为主” 发明者量化兼容麦语言啦!

5年时光 我们裹挟前行。发明者量化从筚路蓝缕到步履蹒跚,从以“区块链资产交易”为阵地,再到以“内外盘商品期货”为依托。再到今天全面兼容“麦语言”。每一步,我们始终都在为建立一个优秀...

酒逢知己千杯少
12分钟前
0
0
session深入探讨

简介 session,会话,其实是一个容易让人误解的词。它总跟web系统的会话挂钩,利用session,javaweb项目实现了登录状态的控制。坊间流传,关闭浏览器,就是关闭了web系统的会话。其实浏览器对...

千里明月
14分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部