SpringMVC之构造映射关系

  springmvc正是通过构造请求的模式和其对应的method,然后通过反射机制执行方法,并将结果返回。

  本篇就分析下映射关系的初始化过程

一 关键类讲解

   HandlerMethod 

public class HandlerMethod {

    /** Logger that is available to subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    private final Object bean;

    private final BeanFactory beanFactory;

    private final Class<?> beanType;

    private final Method method;//实际的method

    private final Method bridgedMethod;

    private final MethodParameter[] parameters;//入参

  它有一个非常重要的子类,  ServletInvocableHandlerMethod 

  ServletInvocableHandlerMethod这个类在HandlerAdapter对每个请求处理过程中,都会实例化一个出来(上面提到的属性由HandlerAdapter进行设置),分别对请求和返回进行处理。  (RequestMappingHandlerAdapter源码,实例化ServletInvocableHandlerMethod的时候分别set了上面提到的重要属性)

   MethodParameter 

public class MethodParameter {

    private final Method method;//方法名

    private final Constructor<?> constructor;

    private final int parameterIndex;//该参数的下标,表示第几个入参

    private int nestingLevel = 1;

    /** Map from Integer level to Integer type index */
    Map<Integer, Integer> typeIndexesPerLevel;

    private volatile Class<?> containingClass;

    private volatile Class<?> parameterType;//类型

    private volatile Type genericParameterType;

    private volatile Annotation[] parameterAnnotations;

    private volatile ParameterNameDiscoverer parameterNameDiscoverer;

    private volatile String parameterName;//参数名

    private volatile MethodParameter nestedMethodParameter;

   RequestMappingInfo   是一个封装了各种请求映射条件并实现了RequestCondition接口的类。

  有各种RequestCondition实现类属性,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,这个请求条件看属性名也了解,分别代表http请求的路径模式、方法、参数、头部等信息。

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

    private final String name;

    private final PatternsRequestCondition patternsCondition;//URL模式 

    private final RequestMethodsRequestCondition methodsCondition;//GET 还是POST

    private final ParamsRequestCondition paramsCondition;

    private final HeadersRequestCondition headersCondition;

    private final ConsumesRequestCondition consumesCondition;

    private final ProducesRequestCondition producesCondition;

   RequestMappingHandlerMapping 

  处理请求与HandlerMethod映射关系的一个类

二 初始化过程

  我们先从命名空间开始说起  

  当要使用mvc都是这么开始的  <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/> 

  熟悉spring的都知道命名空间是怎么回事,直接到jar包的META-INF里去找

   http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler 

  

public class MvcNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
        registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
        registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
        registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
        registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
        registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
        registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
        registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
    }
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {

    public static final String HANDLER_MAPPING_BEAN_NAME = RequestMappingHandlerMapping.class.getName();//默认的bean

    public static final String HANDLER_ADAPTER_BEAN_NAME = RequestMappingHandlerAdapter.class.getName();//默认的bean

  

@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        Object source = parserContext.extractSource(element);
        XmlReaderContext readerContext = parserContext.getReaderContext();

        CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
        parserContext.pushContainingComponent(compDefinition);

        RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);

        RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
        handlerMappingDef.setSource(source);
        handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        handlerMappingDef.getPropertyValues().add("order", 0);
        handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

        if (element.hasAttribute("enable-matrix-variables")) {
            Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
            handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
        }
        else if (element.hasAttribute("enableMatrixVariables")) {
            Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
            handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
        }

        configurePathMatchingProperties(handlerMappingDef, element, parserContext);
        readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);

  上面的代码说明了,在解析   <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>  

  系统自动给容器中注册了两个BeanDefinition,分别是 RequestMappingHandlerMapping ,RequestMappingHandlerAdapter

  接下来我们就分析  RequestMappingHandlerMapping  的初始化过程

三  RequestMappingHandlerMapping 初始化

  初始化的工作在  AbstractHandlerMethodMapping 

@Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }
protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
        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 {
                    beanType = getApplicationContext().getType(beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                if (beanType != null && isHandler(beanType)) {//拿到当前容器的所有的bean,判断是不是controller
                    detectHandlerMethods(beanName);
                }
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

  

protected void detectHandlerMethods(final Object handler) {//handler就是实际的controller实现类
        Class<?> handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        final Class<?> userType = ClassUtils.getUserClass(handlerType);

        Map<Method, T> methods = MethodIntrospector.selectMethods(userType, //这里的methods的结构是key是Method,而Value是一个RequestMappingInfo 
                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);
                        }
                    }
                });//这部分的逻辑并不复杂,就是遍历这个对象里的所有方法,并记录下方法上的路径

        if (logger.isDebugEnabled()) {
            logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
        }
        for (Map.Entry<Method, T> entry : methods.entrySet()) {
            Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
            T mapping = entry.getValue();
            registerHandlerMethod(handler, invocableMethod, mapping);
        }
    }

  我们看一下  RequestMappingHandlerMapping 的

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);
            }
        }
        return info;
    }   

  

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);
    }

  入参 AnnotatedElement 是  public com.suning.rdrs.admin.controller.ResponseResult com.suning.rdrs.admin.controller.audit.RdrsAuditCallbackController.manualAudit(java.lang.String) ,类型就是java反射的Method。

   AnnotatedElementUtils.findMergedAnnotation 的作用就是解析Method带有的RequestMapping注解

  requestMapping的返回值是  @org.springframework.web.bind.annotation.RequestMapping(name=, value=[/alarm/summary], path=[/alarm/summary], method=[GET], params=[], headers=[], produces=[], consumes=[]) 

  我这里的condition是null,因为我没有配特殊模式

  然后就是构造RequestMappingInfo

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

        return RequestMappingInfo
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                .methods(requestMapping.method())
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name())
                .customCondition(customCondition)
                .options(this.config)
                .build();
    }

  整个过程最后我们得到  Map<Method, T> methods  key是Method,Value是RequestMappingInfo

  让我们回到  AbstractHandlerMethodMapping.detectHandlerMethods 看看剩下的部分

for (Map.Entry<Method, T> entry : methods.entrySet()) {
            Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
            T mapping = entry.getValue();
            registerHandlerMethod(handler, invocableMethod, mapping);
        }

   AbstractHandlerMethodMapping 中的方法

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

  

public void register(T mapping, Object handler, Method method) {
            this.readWriteLock.writeLock().lock();
            try {
                HandlerMethod handlerMethod = createHandlerMethod(handler, method);
                assertUniqueMethodMapping(handlerMethod, mapping);

                if (logger.isInfoEnabled()) {
                    logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
                }
                this.mappingLookup.put(mapping, handlerMethod); //key是RequestMappingInfo对象,Value是实际的方法

                List<String> directUrls = getDirectUrls(mapping);
                for (String url : directUrls) {
                    this.urlLookup.add(url, mapping); //保存url和mapping关系注意 mapping是一个RequestMappingInfo对象
                }

                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<T>(mapping, handlerMethod, directUrls, name));
            }
            finally {
                this.readWriteLock.writeLock().unlock();
            }
        }

  以上就是分析怎么把请求url和对应的处理方法关联起来的,这里面有很多细节比如RequestMappingInfo在构建中,有些用户会写很复杂的url模式,比如带通配符的,通配符还有很多钟模式等等。本文要讨论的是原理,哪些字符串解析就不管他了。

  

posted on 2020-12-07 12:06  MaXianZhe  阅读(245)  评论(0编辑  收藏  举报

导航