SpringMVC源码分析(三)--RequestMappingHandlerMapping

默认情况下DispatcherServlet会注册3个HandlerMapping,分别是BeanNameUrlHandlerMapping、RequestMappingHandlerMapping及RouterFunctionMapping

HandlerMapping的作用是存储请求路径与处理方法的映射,收到请求后就能通过HandlerMapping找到对应的处理方法

本节我们主要分析RequestMappingHandlerMapping的作用及其原理

1.RequestMappingHandlerMapping的作用

RequestMappingHandlerMapping处理通过Controller注解的类中RequestMapping注解标注的方法,这也是我们平时使用最多的场景,例如:

@Controller
public class Controller01 {
    @GetMapping("/test01")
    public void test(HttpServletResponse response) throws IOException {
        response.getWriter().print("hello test01");
    }
}

配置类及测试代码参考前文SpringMVC源码分析(一)--基本组件

浏览器输入http://127.0.0.1:8080/test01,页面即可响应hello test01

2.RequestMappingHandlerMapping原理

在DispatcherServlet初始化中,会初始化每个HandlerMapping实现类

RequestMappingHandlerMapping是HandlerMapping的实现类,同时它也实现了InitializingBean接口,因此创建时会调用afterPropertiesSet进行初始化

public void afterPropertiesSet() {
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(useSuffixPatternMatch());
    this.config.setTrailingSlashMatch(useTrailingSlashMatch());
    this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    // 调用AbstractHandlerMethodMapping的初始化方法
    super.afterPropertiesSet();
}

父类初始化代码见AbstractHandlerMethodMapping#afterPropertiesSet,会筛选出控制器类,并检测其中的处理方法

public void afterPropertiesSet() {
    initHandlerMethods();
}

protected void initHandlerMethods() {
    // 1.获取候选的beanName
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            // 2.处理候选的bean
            processCandidateBean(beanName);
        }
    }
    // 3.初始化后处理,可通过子类扩展,这里仅打印日志
    handlerMethodsInitialized(getHandlerMethods());
}

protected String[] getCandidateBeanNames() {
    // 从容器中获取所有BeanName
    // this.detectHandlerMethodsInAncestorContexts为true表示需要从所有父容器和当前容器中查找
    // this.detectHandlerMethodsInAncestorContexts为false表示只从当前容器中查找
    return (this.detectHandlerMethodsInAncestorContexts ?
        BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
        obtainApplicationContext().getBeanNamesForType(Object.class));
}

protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    // 判断是不是请求控制器
    if (beanType != null && isHandler(beanType)) {
        // 检测控制器类中的处理方法
        detectHandlerMethods(beanName);
    }
}

protected boolean isHandler(Class<?> beanType) {
    // bean的类上如果有Controller注解、Controller的派生注解(例如RestController等)、
    // RequestMapping注解、RequestMapping的派生注解(例如GetMapping等)
    // 那么就是控制器
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
        AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

protected void detectHandlerMethods(Object handler) {
    // 获取控制器类,如果是字符串,说明是类名,则根据类名从容器中获取控制器类对象
    Class<?> handlerType = (handler instanceof String ?
        obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        // 如果是Cglib的代理类,则获取父类
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 核心方法:查找处理方法
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
        (MethodIntrospector.MetadataLookup<T>) method -> {
            try {
                return getMappingForMethod(method, userType);
            }
            catch (Throwable ex) {
                throw new IllegalStateException("Invalid mapping on handler class [" +
                    userType.getName() + "]: " + method, ex);
            }
        });
        if (logger.isTraceEnabled()) {
            logger.trace(formatMappings(userType, methods));
        }
        methods.forEach((method, mapping) -> {
            // 查找userType类中是否存在method方法
            // 如果不存在则去userType的父接口中寻找是否存在,存在即返回,否则抛出异常
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 核心方法:注册方法信息
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

具体看一下是如何查找处理方法的,源码见MethodIntrospector#selectMethods

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
    final Map<Method, T> methodMap = new LinkedHashMap<>();
    Set<Class<?>> handlerTypes = new LinkedHashSet<>();
    Class<?> specificHandlerType = null;

    // 如果不是jdk动态代理的代理类
    if (!Proxy.isProxyClass(targetType)) {
        // 如果是cglib动态代理的代理类,则返回父类
        specificHandlerType = ClassUtils.getUserClass(targetType);
        // 添加specificHandlerType到handlerTypes中
        handlerTypes.add(specificHandlerType);
    }
    // 添加所有接口到handlerTypes中
    handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

    for (Class<?> currentHandlerType : handlerTypes) {
        final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
        ReflectionUtils.doWithMethods(currentHandlerType, method -> {
            Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
            // 判断这个方法是否是请求处理方法,如果不是返回空,这里调用的是getMappingForMethod(method, userType)
            T result = metadataLookup.inspect(specificMethod);
            if (result != null) {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                    // 添加到methodMap中
                    methodMap.put(specificMethod, result);
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
   }

   return methodMap;
}

metadataLookup.inspect调用的是RequestMappingHandlerMapping#getMappingForMethod

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 判断是否是请求处理方法,如果是则返回RequestMappingInfo,其中封装了方法上的RequestMapping注解信息
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 封装类上的RequestMapping注解信息
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            // 合并类和方法上的RequestMapping注解信息
            info = typeInfo.combine(info);
        }
        /**
        * 如果该控制器类有路径前缀的配置,场景是创建RequestMappingHandlerMapping对象时可以设置控制器的前缀路径
        * 例如:
        * @Bean
        * public HandlerMapping requestHandlerMapping() {
        *     RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
        *     Map<String, Predicate<Class<?>>> map = new HashMap<>();
        *     map.put("/bbb", clazz -> clazz.getName().contains("Controller01"));
        *     requestMappingHandlerMapping.setPathPrefixes(map);
        *     return requestMappingHandlerMapping;
        * }
        * 这个时候就会将/bbb添加到此路径前缀中
        */ 
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            // 合并路径前缀到info中
            info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
        }
    }
    return info;
}

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    // 判断逻辑是在方法上查找是否有RequestMapping注解或其派生注解
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    RequestCondition<?> condition = (element instanceof Class ?
        getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    // 封装方法上的RequestMapping注解中的参数信息
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

最后注册方法委托给内部的成员变量mappingRegistry去完成

private final MappingRegistry mappingRegistry = new MappingRegistry();

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}

实际调用的是MappingRegistry#register进行方法注册

public void register(T mapping, Object handler, Method method) {
    if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
        Class<?>[] parameterTypes = method.getParameterTypes();
        if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
            throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
        }
    }
    this.readWriteLock.writeLock().lock();
    try {
        // 将执行方法封装成HandlerMethod对象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        // 校验mapping是否已存在,存在会抛出异常,保证mapping唯一
        validateMethodMapping(handlerMethod, mapping);
        // 注册到mappingLookup集合中
        this.mappingLookup.put(mapping, handlerMethod);
        
        // 提取出url
        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            // 注册到urlLookup集合中
            this.urlLookup.add(url, mapping);
        }
        
        String name = null;
        if (getNamingStrategy() != null) {
            // 如果namingStrategy不为空,获取到name,注册到nameLookup集合中
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }
        
        // 注册跨域配置
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        
        // 注册到registry集合中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

至此,请求映射注册完成,总结下流程:

  1. DispatcherServlet初始化时会初始化容器中所有的HandlerMapping
  2. RequestMappingHandlerMapping在初始化时会遍历容器中所有的bean,筛选出符合条件的控制器方法,即类上有Controller或其派生注解且方法上有RequestMapping注解或其派生注解
  3. 通过MappingRegistry将这些符合条件的方法注册到集合中

当DispatcherServlet收到请求时,会调用getHandler()获取对应的处理方法,源码见DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    
    // 省略其他代码...
    
    // 获取方法执行器
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) {
        noHandlerFound(processedRequest, response);
        return;
    }
    
    // 省略其他代码...
}

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历容器中的HandlerMapping
        for (HandlerMapping mapping : this.handlerMappings) {
            // 从HandlerMapping中获取方法执行器
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

mapping.getHandler(request)是模板方法,源码见AbstractHandlerMapping#getHandler

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 子类实现,获取HandlerMethod,关键方法
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // 如果是字符串,则从容器中获取对应的bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    
    // 封装为HandlerExecutionChain 
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    
    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }
    
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    
    return executionChain;
}

RequestMappingInfoHandlerMapping#getHandlerInternal获取HandlerMethod实现是:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    try {
        // 调用AbstractHandlerMapping的getHandlerInternal
        return super.getHandlerInternal(request);
    }
    finally {
        ProducesRequestCondition.clearMediaTypesAttribute(request);
    }
}

调用父类的getHandlerInternal,源码见AbstractHandlerMapping#getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 解析出请求路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根据请求信息查找HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 从urlLookup中查找有没有注册这个路径
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 将匹配的处理器方法添加到matches中
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 如果通过urlLookup没有找到,则遍历所有mappingLookup,看有没有匹配的
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    // 如果找到了匹配的处理器方法
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        // 校验
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                    "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        // 返回匹配的处理器方法
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    for (T mapping : mappings) {
        // 匹配RequestMappingInfo和request,如果匹配上则返回RequestMappingInfo,没有匹配上返回null
        T match = getMatchingMapping(mapping, request);
        if (match != null) {
            matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
        }
    }
}

获取到HandlerMethod之后,会被封装成HandlerExecutionChain对象

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 创建HandlerExecutionChain对象
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
        (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    // 添加HandlerInterceptor
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

最后将HandlerExecutionChain对象交给HandlerAdapter去执行,这部分将在HandlerAdapter篇章中详述

  • 39
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lm_ylj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值