SpringMVC源码(五)- doDispatch - getHandler的准备阶段(@RequestMapping解析注册)

目录

一、doDispatch的getHandler

1、RequestMappingHandlerMapping结构

2、setApplicationContext回调函数

3、afterPropertiesSet回调函数

1)、获取可能的类

2)、解析和注册

3)、递归查询所有的方法

4)、将RequestMapping注解修饰的方法以RequestMappingInfo返回

5)、注册调用方法

二、doDispatch的getHandlerAdapter

1、RequestMappingHandlerAdapter

2、HandlerFunctionAdapter

3、HttpRequestHandlerAdapter

4、SimpleControllerHandlerAdapter

5、SimpleServletHandlerAdapter

三、总结


一、doDispatch的getHandler

    SpringMVC中比较重要的就是doDispatch,而其中第一个比较重要的就是根据HttpServletRequest(当前为RequestFacade类型)获取HandlerExecutionChain(调用的Controller和需要调用的HandlerInterceptor链)。

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

    遍历所有的加载HandlerMapping子类列表,调用HandlerMapping定义的getHandler方法,如果不为null则适配成功。现在主要使用@RequestMapping形式的对应的HandlerMapping为RequestMappingHandlerMapping类型。 

 

1、RequestMappingHandlerMapping结构

1、实现了ApplicationContextAware接口,回调setApplicationContext方法时。赋值ApplicationContext给后面的afterPropertiesSet回调,从BeanFactory中获取Object类型的所有Bean做准备;并且完成了所有HandlerInteceptor的初始化。

2、实现了InitializingBean,并且在getBean时的afterPropertiesSet回调中完成了请求调用前的准备工作。将Bean 中的@RequestMapping解析为RequestMappingInfo。

3、实现了HandlerMapping接口,请求调用时getHandler获取到匹配的具体调用方法和拦截器执行链

 

2、setApplicationContext回调函数

@Override
public final void setApplicationContext(@Nullable ApplicationContext context)
    throws BeansException {
    // 省略
    } else if (this.applicationContext == null) {
        // Initialize with passed-in context.
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException("省略");
        }
        this.applicationContext = context;
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        initApplicationContext(context);
    } // 省略
}

    主要会对ApplicationContext进行赋值;初始化MessageSourceAccessor对象;并且调用自定义的初始化方法。

protected void initApplicationContext(ApplicationContext context) throws BeansException {
    initApplicationContext();
}
@Override
protected void initApplicationContext() throws BeansException {
    extendInterceptors(this.interceptors);
    detectMappedInterceptors(this.adaptedInterceptors);
    initInterceptors();
}

    全是对HandlerIntecepter的处理:

    1)、extendInterceptors为空方法,子类没有实现

    2)、将BeanFactory中所有MappedInterceptor类型的Bean加载进来

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    mappedInterceptors.addAll(
        BeanFactoryUtils.beansOfTypeIncludingAncestors(
            obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

    3)、其他地方都是调用方法将HandlerInteceptor加入到interceptors集合中,现在是将里面的所以对象都适配到adaptedInterceptors中,方法调用时在该集合中匹配处理。

protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("省略");
            }
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

        适配方法adaptInterceptor如下:

protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    if (interceptor instanceof HandlerInterceptor) {
        return (HandlerInterceptor) interceptor;
    } else if (interceptor instanceof WebRequestInterceptor) {
        return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    } else {
        throw new IllegalArgumentException("省略");
    }
}

 

3、afterPropertiesSet回调函数

@Override
public void afterPropertiesSet() {
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());

    super.afterPropertiesSet();
}

    完成配置的初始化(后续getHandler是需要的工具)后,就调用父类的afterPropertiesSet方法。

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}
protected void initHandlerMethods() {
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

    1)、拿到所有可能被会有调用方法的类

    2)、获取注解方法,并注册到mappingRegistry中

    3)、日志打印解析的handlerMethods的总数

1)、获取可能的类

protected String[] getCandidateBeanNames() {
    return (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
            obtainApplicationContext().getBeanNamesForType(Object.class));
}

    该参数默认为false,基本都会调用后面的逻辑。获取BeanFactory中所有Object类型的Bean(差不多又是暴力的获取全部)。

2)、解析和注册

protected void processCandidateBean(String beanName) {
    // 省略try catch代码
    Class<?> beanType = obtainApplicationContext().getType(beanName);
    if (beanType != null && isHandler(beanType)) {
        detectHandlerMethods(beanName);
    }
}

    从BeanFactory中获取对应的Bean,在调用detectHandlerMethods方法:

protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ?
            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                (MethodIntrospector.MetadataLookup<T>) method -> {
                    // 省略try catch的代码
                   return getMappingForMethod(method, userType);
                });
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

    1、先获取对应的Class

    2、根据Class先获取真实的Class(cglib中包含$$字符);再递归(递归时可能有代理,也要获取真实的Class)获取所有的方法;再判断是否存在@RequestMap注解,则创建RequestMappingInfo对象,返回MethodRequestMappingInfo的Map键值对。

    3、注册HandlerMethod

3)、递归查询所有的方法

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;

    if (!Proxy.isProxyClass(targetType)) {
        specificHandlerType = ClassUtils.getUserClass(targetType);
        handlerTypes.add(specificHandlerType);
    }
    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);
            T result = metadataLookup.inspect(specificMethod);
            if (result != null) {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                    methodMap.put(specificMethod, result);
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
    }

    return methodMap;
}

 

4)、将RequestMapping注解修饰的方法以RequestMappingInfo返回

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            info = typeInfo.combine(info);
        }
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).build().combine(info);
        }
    }
    return info;
}

    先根据Method调用创建,再用Class调用创建,并调用combine方法设置到父RequestMappingInfo。

@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    RequestCondition<?> condition = (element instanceof Class ?
            getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

    判断方法上是否有@RequestMapping注解,有则获取注解,并将其封装为RequestMappingInfo对象。

protected RequestMappingInfo createRequestMappingInfo(
        RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

    RequestMappingInfo.Builder builder = RequestMappingInfo
            .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
            .methods(requestMapping.method())
            .params(requestMapping.params())
            .headers(requestMapping.headers())
            .consumes(requestMapping.consumes())
            .produces(requestMapping.produces())
            .mappingName(requestMapping.name());
    if (customCondition != null) {
        builder.customCondition(customCondition);
    }
    return builder.options(this.config).build();
}

 

5)、注册调用方法

methods.forEach((method, mapping) -> {
    Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    registerHandlerMethod(handler, invocableMethod, mapping);
});

    如果方法是被代理的,则获取真实的方法。再进行注册:

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
    // Assert that the handler method is not a suspending one.
    if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
        throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
    }
    this.readWriteLock.writeLock().lock();
    try {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        validateMethodMapping(handlerMethod, mapping);
        this.mappingLookup.put(mapping, handlerMethod);

        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }

        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

    1、打开写锁(getHandler进行匹配时,使用读锁)

    2、创建HandlerMethod对象(就是我们@RequestMapping注解的字符串和Method

new HandlerMethod(handler, method)

    3、mappingLookup添加注册数据(RequestMappingInfo 和 HandlerMethod的关系

// mapping为之前创建的 RequestMappingInfo 对象
this.mappingLookup.put(mapping, handlerMethod);

    4、urlLookup添加注册数据(@RequestMapping类将的加上方法上的字符串和)

// url为@RequestMapping类上加上方法上的字符串;mapping为当前Bean的名称
this.urlLookup.add(url, mapping);

    5、获取策略,拼装该方法的请求url

String name = null;
// 策略为RequestMappingInfoHandlerMethodMappingNamingStrategy
if (getNamingStrategy() != null) {
    // 获取策略名称
    name = getNamingStrategy().getName(handlerMethod, mapping);
    // 注册到nameLookup容器中
    addMappingName(name, handlerMethod);
}

    根据策略RequestMappingInfoHandlerMethodMappingNamingStrategy调用getName方法,比如:

类上的注解为:@RequestMapping("threadDemoController")

方法上注解为:@GetMapping("threadDemo")

当前名称为:TDC#getUser       

拼装规则为: 类上的注解字符串的每个字母的大写  + # + 当前方法名称

    再添加到nameLookup容器中(如果之前的List中有数据则,添加完之后为原数据 + 现有数据)。

 

    6、处理cors跨域(后续再分析)

    7、注册MappingRegistration类型的对象,key为之前创建的RequestMappingInfo对象。

 

二、doDispatch的getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("省略");
}

    遍历所有注入的HandlerAdapter,调用support进行判断,不同类型实现不同。 得到适配器之后,主要的是调用handler方法进行具体方法的调用处理,单主要是通过解析后handler的类型进行判断,可以参考SpringMVC源码(四)- 常用HandlerMapping和HandlerAdaptor组合和使用方式

1、RequestMappingHandlerAdapter

@Override
public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

    如果是使用@RequestMapping解析后得到的为HandlerMethod类型,所以直接进行判断。并且调用supportsInternal方法:

@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}

2、HandlerFunctionAdapter

@Override
public boolean supports(Object handler) {
    return handler instanceof HandlerFunction;
}

3、HttpRequestHandlerAdapter

@Override
public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}

    直接判断解析后的handler,是否是实现了接口HttpRequestHandler。

4、SimpleControllerHandlerAdapter

@Override
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}

    同样直接判断是否实现了Controller接口。

5、SimpleServletHandlerAdapter

@Override
public boolean supports(Object handler) {
    return (handler instanceof Servlet);
}

    同样直接判断是否实现了Servlet接口,其HttpServlet的顶层父类包含Servlet。

 

三、总结

    前提:SpringMVC在初始化DispatcherServlet的init方法时,间接的将九大件初始化,其中就包括了HandlerMapping中的RequestMappingHandlerMapping类型。

    1、setApplicationContext回调方法中,初始化完成了所有的HandlerInteceptor

    2、afterPropertiesSet回调方法中,从BeanFactory中获取到所有的Bean。遍历所有的类,再递归遍历所有的父类,将有@RequestMapping的方法创建为RequestMappingInfo类型,注册到时又先创建HandlerMethod对象,再以MappingRegistration的形式注册到内部属性mappingRegistry中(key为RequestMappingInfo,value为MappingRegistration)。

    3、当方法调用(getHandler)时,将HTTPServletRequest解析适配对应的HandlerMethod和需要执行的拦截器调用链(下一篇继续解析)。

    3)、一切准备就绪,待RequestMappingHandlerAdapter的适配,调用具体的方法。

 

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值