文档章节

3 HandlerMapping 组件源码分析

java_sheng
 java_sheng
发布于 2017/08/30 20:41
字数 902
阅读 2
收藏 0
点赞 0
评论 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处理静态资源,主要是两个标签,mvc:resources和mvc:default-servlet-handler。在详细说明他们的原理之前,需要先简单说明下SpringMVC中请求处理机制:HandlerMapping和HandlerAdap...

乒乓狂魔 ⋅ 2015/03/18 ⋅ 1

Spring 源码分析(四) ——MVC(五)初始化阶段

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

水门-kay ⋅ 2016/04/02 ⋅ 0

【原创】遨游springmvc之HandlerMapping

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

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

Spring3.2 MVC 分析

Spring3.2 MVC 分析: SpringMVC现在应该用得很广泛了,其配置清晰,灵活度,定制能力等都是很强的,相比Struts2也是胜过一筹,还是从源码来分析一下,SpringMVC为我们做了什么。 先从配置文...

ihaolin ⋅ 2014/02/03 ⋅ 2

springmvc学习笔记(4)-前端控制器

springmvc学习笔记(4)-前端控制器 标签: springmvc [TOC] 本文通过前端控制器源码分析springmvc执行过程 1.前端控制器接收请求 调用方法 2.前端控制器调用(处理器映射器)根据url查找Handl...

brianway ⋅ 2016/03/09 ⋅ 0

SpringMVC架构原理分析

springmvc框架原理(掌握) 前端控制器、处理器映射器、处理器适配器、视图解析器 springmvc入门程序 目的:对前端控制器、处理器映射器、处理器适配器、视图解析器学习;非注解的处理器映射...

小小蒜头 ⋅ 2017/11/30 ⋅ 0

SpringMVC源码系列:HandlerMapping

HandlerMapping接口是用来查找Handler的。在SpringMvc中,DispatcherServlet处理分发很多请求,而每个请求都需要一个Handler来处理,具体接受到一个请求后使用哪个Handler来处理呢?这就是H...

glmapper_2018 ⋅ 01/11 ⋅ 0

spring boot 2.x静态资源会被HandlerInterceptor拦截的原因和解决方法

在spring boot 1.5.x中,resources/static目录下的静态资源可以直接访问,并且访问路径上不用带static,比如静态资源放置位置如下图所示: 那么访问静态资源的路径可以是: http://localhost...

Mr---D ⋅ 04/13 ⋅ 0

Spring MVC源码学习一之初始化

一、简单提下使用入门(依赖于注解方式) 1、通过在web.xml中添加配置,引入spring mvc框架,类似于Struts2引入需要在web.xml中配置过滤器StrutsPrepareAndExecuteFilter一样,但是Spring MVC是...

silence88 ⋅ 2016/12/20 ⋅ 1

SpringMVC源码系列:AbstractHandlerMapping

AbstractHandlerMapping是实现HandlerMapping接口的一个抽象基类。支持排序,默认处理程序,处理程序拦截器,包括由路径模式映射的处理程序拦截器。所有的HandlerMapping都继承自AbstractHan...

glmapper_2018 ⋅ 01/11 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从 Confluence 5.3 及其早期版本中恢复空间

如果你需要从 Confluence 5.3 及其早期版本中的导出文件恢复到晚于 Confluence 5.3 的 Confluence 中的话。你可以使用临时的 Confluence 空间安装,然后将这个 Confluence 安装实例升级到你现...

honeymose ⋅ 14分钟前 ⋅ 0

用ZBLOG2.3博客写读书笔记网站能创造今日头条的辉煌吗?

最近两年,著名的自媒体网站今日头条可以说是火得一塌糊涂,虽然从目前来看也遇到了一点瓶颈,毕竟发展到了一定的规模,继续增长就更加难了,但如今的今日头条规模和流量已经非常大了。 我们...

原创小博客 ⋅ 今天 ⋅ 0

MyBatis四大核心概念

本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper)。 MyBatis 作为互联网数据库映射工具界的“上古神器”,训有四大“神兽”,谓之:Sql...

waylau ⋅ 今天 ⋅ 0

以太坊java开发包web3j简介

web3j(org.web3j)是Java版本的以太坊JSON RPC接口协议封装实现,如果需要将你的Java应用或安卓应用接入以太坊,或者希望用java开发一个钱包应用,那么用web3j就对了。 web3j的功能相当完整...

汇智网教程 ⋅ 今天 ⋅ 0

2个线程交替打印100以内的数字

重点提示: 线程的本质上只是一个壳子,真正的逻辑其实在“竞态条件”中。 举个例子,比如本题中的打印,那么在竞态条件中,我只需要一个方法即可; 假如我的需求是2个线程,一个+1,一个-1,...

Germmy ⋅ 今天 ⋅ 0

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 今天 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部