美文网首页
HandlerMapping

HandlerMapping

作者: 回文体文回 | 来源:发表于2018-07-15 13:29 被阅读0次

前言

我们已经知道HandlerMapping的主要作用是通过request找到Handler,Spring MVC中HandlerMapping的实现有很多,比如SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping以及RequestMappingHandlerMapping等等,本篇文章就来分析下最常用的RequestMappingHandlerMapping。

RequestMappingHandlerMapping

我们先来看下RequestMappingHandlerMapping的继承关系,然后从继承关系从上到下依次分析。

RequestMappingHandlerMapping继承关系

HandlerMapping

HandlerMapping我们已经分析过了,不过最好还是回顾下接口的定义

public interface HandlerMapping {

    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

    String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";

    String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";

    String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

    String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";

    String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

AbstractHandlerMapping

创建过程

AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化的时候会调用initApplicationContext,其内部主要是初始化interceptors,供以后使用。

Interceptor分为两种

  • 一种是直接或间接实现了Interceptor接口的普通拦截器,它对所有的请求都会拦截
  • 另一种是MappedInterceptor,MappedInterceptor内部包含一个第一种的拦截器,但是它有一个matches方法,只有符合要求的请求它才会拦截
    protected void initApplicationContext() throws BeansException {
        // 模板方法,用于子类扩展或修改interceptors,不过并没有子类实现
        extendInterceptors(this.interceptors);
        // 将ApplicationContext中所有的MappedInterceptor添加到adaptedInterceptors中
        detectMappedInterceptors(this.adaptedInterceptors);
        // 将interceptors中的元素添加到adaptedInterceptors中
        initInterceptors();
    }
使用过程

AbstractHandlerMapping实现了getHandler方法,主要分为两个部分

  1. 获取Handler,这部分是模板方法,由子类实现
  2. 将创建过程中初始化的interceptors和第一步获取的handler一起组成HandlerExecutionChain
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 模板方法,由子类实现
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            // 获取默认Handler,默认为null
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // handler是beanName,就从ApplicationContext中取出对应的bean
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }

        // 通过handler和request获取HandlerExecutionChain
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        // 如果是cors请求,添加一些拦截器
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }

现在我们再来看下获取HandlerExecutionChain的具体过程,第一步是构造HandlerExecutionChain,第二步是根据情况添加拦截器。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        // 构造HandlerExecutionChain
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        // 添加拦截器
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            // 添加符合条件的MappedInterceptor
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            } else {
                // 非MappedInterceptor都添加进来
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

AbstractHandlerMethodMapping

我们先来解释下AbstractHandlerMethodMapping中泛型T的含义,官方定义为The mapping for a HandlerMethod containing the conditions needed to match the handler method to incoming request,也就是它是一个包含了各种条件(包括url、HttpMethod、Header等)的一个类,通过这个类可以找到一个HandlerMethod(一种Handler),T默认的实现是RequestMappingInfo。

创建过程

AbstractHandlerMethodMapping实现了InitializingBean,所以它的初始化入口是
afterPropertiesSet,其内部只是简单地调用了initHandlerMethods方法,并没有做其他操作,下面我们来看下initHandlerMethods的具体实现

    protected void initHandlerMethods() {
        // 找到ApplicationContext中所有的beanName
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));

        for (String beanName : beanNames) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                Class<?> beanType = null;
                try {
                    // 获取到bean
                    beanType = getApplicationContext().getType(beanName);
                }
                catch (Throwable ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                // isHandler是模板方法
                if (beanType != null && isHandler(beanType)) {
                    // 将bean中符合条件的方法注册到mappingRegistry
                    detectHandlerMethods(beanName);
                }
            }
        }
        // 对handler做一些初始化操作,模板方法,并没有子类实现
        handlerMethodsInitialized(getHandlerMethods());
    }

这里说一下isHandler方法,它由RequestMappingHandlerMapping实现,可以看出它的判断依据是类上是否有@Controller或@RequestMapping注解。

    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

下面我们再来具体看下detectHandlerMethods方法

    protected void detectHandlerMethods(final Object handler) {
        // 获取handler的类
        Class<?> handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        // 如果是cglib代理的子类,则返回父类,否则直接返回传入的类
        final Class<?> userType = ClassUtils.getUserClass(handlerType);

        // 获取所有符合条件的方法以及对应的匹配条件
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                new MethodIntrospector.MetadataLookup<T>() {
                    @Override
                    public T inspect(Method method) {
                        try {
                            // 模板方法,返回方法对应的匹配条件
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    }
                });
        // 注册到mappingRegistry
        for (Map.Entry<Method, T> entry : methods.entrySet()) {
            Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
            T mapping = entry.getValue();
            registerHandlerMethod(handler, invocableMethod, mapping);
        }
    }

其实我们可以总结出AbstractHandlerMethodMapping的创建过程其实就是根据代码里@Controller和@RequestMapping注解,将符合条件的方法包装成HandlerMethod,并且建立HandlerMethod和T的对应关系。

AbstractHandlerMethodMapping的使用过程

从AbstractHandlerMapping的使用过程我们知道,AbstractHandlerMethodMapping使用的入口是getHandlerInternal方法

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        // 获取lookupPath,可以简单理解成url
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        this.mappingRegistry.acquireReadLock();
        try {
            // 通过lookupPath和request中的一些条件(比如是GET请求还是POST请求等)找到HandlerMethod
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }

RequestMappingInfoHandlerMapping

RequestMappingHandlerMapping

相关文章

网友评论

      本文标题:HandlerMapping

      本文链接:https://www.haomeiwen.com/subject/aevqlftx.html