SpringMVC配置文件解析(三)

前言

前面的两篇文章分别介绍了配置文件注册bean的过程以及注解注册Bean的过程。

那么现在就将目光转向SpringMVC配置文件的具体配置吧。

一般来说,我们在编写SpringMVC配置文件的时候都会被建议加上入下的配置:

    <mvc:annotation-driven/>

那有没有人想过为什么要加这个配置呢,这个标签到底起什么作用呢,我们今天就来探究一下。

mvc:annotation-driven的解析

在上一篇我们已经讲解过了context:component-scan的解析过程。这两个标签都属于扩展标签。

他们的解析都是使用BeanDefinitionParser的相应实现类来解析的,只是他们对应着不同的实现类。

context:component-scan对应着的是ComponentScanBeanDefinitionParser,而mvc:annotation-driven对应的是BeanDefinitionParser的子类org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser

至于是如何找到这个类来解析这个标签的就不多说了,和之前的一样呗。直接来看parse方法

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

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

        RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
        //第一个在这 RequestMappingHandlerMapping 

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

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

        RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
        RuntimeBeanReference validator = getValidator(element, source, parserContext);
        RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

        RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
        bindingDef.setSource(source);
        bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        bindingDef.getPropertyValues().add("conversionService", conversionService);
        bindingDef.getPropertyValues().add("validator", validator);
        bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

        ManagedList messageConverters = getMessageConverters(element, source, parserContext);
        ManagedList argumentResolvers = getArgumentResolvers(element, parserContext);
        ManagedList returnValueHandlers = getReturnValueHandlers(element, parserContext);
        String asyncTimeout = getAsyncTimeout(element);
        RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
        ManagedList callableInterceptors = getCallableInterceptors(element, source, parserContext);
        ManagedList deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
        //第二个在这 RequestMappingHandlerAdapter 

        RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
        handlerAdapterDef.setSource(source);
        handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
        handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
        handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
        addResponseBodyAdvice(handlerAdapterDef);

        if (element.hasAttribute("ignore-default-model-on-redirect")) {
            Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
            handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
        }
        else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
            // "ignoreDefaultModelOnRedirect" spelling is deprecated
            Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
            handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
        }

        if (argumentResolvers != null) {
            handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
        }
        if (returnValueHandlers != null) {
            handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
        }
        if (asyncTimeout != null) {
            handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
        }
        if (asyncExecutor != null) {
            handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
        }

        handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
        handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
        String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);

        String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
        RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
        uriCompContribDef.setSource(source);
        uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
        uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
        parserContext.getReaderContext().getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef);

        RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
        csInterceptorDef.setSource(source);
        csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
        RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
        mappedCsInterceptorDef.setSource(source);
        mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
        mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
        String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
        //异常处理解析器 

        RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
        exceptionHandlerExceptionResolver.setSource(source);
        exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
        exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
        exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
        addResponseBodyAdvice(exceptionHandlerExceptionResolver);

        String methodExceptionResolverName =
                parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
        //异常处理解析器 

        RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
        responseStatusExceptionResolver.setSource(source);
        responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        responseStatusExceptionResolver.getPropertyValues().add("order", 1);
        String responseStatusExceptionResolverName =
                parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
        //异常处理解析器 

        RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
        defaultExceptionResolver.setSource(source);
        defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        defaultExceptionResolver.getPropertyValues().add("order", 2);
        String defaultExceptionResolverName =
                parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);

        parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName));
        parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
        parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
        parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
        parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
        parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
        parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));

        // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
        MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

        parserContext.popAndRegisterContainingComponent();

        return null;
    }

这个方法是不是巨长,其实他的主要工作就是注册了

RequestMappingHandlerMapping   

BeanNameUrlHandlerMapping  

RequestMappingHandlerAdapter  

HttpRequestHandlerAdapter  

SimpleControllerHandlerAdapter  

ExceptionHandlerExceptionResolver   

ResponseStatusExceptionResolver   

DefaultHandlerExceptionResolver   

这八个实例到BeanFactory,即Spring容器中。

前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个是处理@RequestMapping注解的。第二个会将controller类的名字映射为请求url。中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。第一个处理@Controller注解的处理器,支持自定义方法参数和返回值。第二个是处理继承HttpRequestHandler的处理器。第三个处理继承自Controller接口的处理器。后面三个是用来处理异常的解析器。

讲到这里,我们需要回到我们之前讲的DispatchServlet初始化过程了。

DispatchServlet初始化过程中handlerMappings和handlerAdapters属性的注入

我们回到初始化DispatchServlet时FrameWorkServlet的initWebApplicationContext方法

protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

//...非重点代码省略
        if (wac == null) {
            // No context instance was injected at construction time -> see if one
            // has been registered in the servlet context. If one exists, it is assumed
            // that the parent context (if any) has already been set and that the
            // user has performed any initialization such as setting the context id
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one
            wac = createWebApplicationContext(rootContext);
        }

        if (!this.refreshEventReceived) {
            // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            onRefresh(wac);
        }


        return wac;
    }

这个方法的createWebApplicationContext方法我们已经在这个系列的第一篇分析过了,接下来该到onRefresh方法了,我们发现这个方法在FrameWorkServlet中是个空方法,具体实现在DispatchServlet中。

    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }

我们看到有initHandlerMappings方法和initHandlerAdapters方法

这两个方法就是注入handlerMappings属性和handlerAdapters属性的地方。

我们先来看看initHandlerMappings

initHandlerMappings

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            Map matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                OrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

1.先去我们的Beanfactory里面找是不是已经由HandlerMapping类型的Bean已经注入到Spring容器中了,如果有就把他们放入到handlerMappings属性中,而放入之前,需要经过排序,排序的依据就是order属性,order值越小,优先级越高,我们这里有两个HandlerMapping类型的Bean注入,分别是RequestMappingHandlerMapping(order为0),BeanNameUrlHandlerMapping(order为2)。

2.如果并没有已经注入的bean,那么就去Spring容器里去寻找是否有beanName为handlermapping,并且类型是HandlerMapping的Bean,如果有,就把这个Bean注入到handlerMapping属性中。

3.如果以上两种方式都找不到相应的bean,就要使用默认的注册方式了。

默认的注册方式我就不具体说了,可以看看源代码,就是注入DispatchServlet.properties指定的HandlerMapping类型的类到handlerMappings属性中。

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

所以分析到这里,至少我们可以得出一个结论,就算我们没有使用这个标签来进行配置,照样不会对我们的程序产生影响,一样不会让我们得到一个空的handlerMappings,会有默认的初始化方式,而这种标签的配置也是在spring3.1之后再有的,直接就一直使用上述的配置文件进行默认初始化,所以增加了这个标签就是改变了处理请求的类而已。

对注入handlerAdapters就不具体分析了,只说一下,他们也需要使用order排序,但是默认情况下,order都是Integer.MAX,并没有显式给定order值。一般情况下,也不需要优先级,因为一种adapter只支持一种handler。

其实到这里,我们也算把DispatchServlet的初始化过程讲的差不多了,那我们接下来就来简单分析下对请求的处理吧。

使用RequestMappingHandlerMapping和RequestMappingHandlerAdapter处理请求

我们在上面分析了HandlerMapping的优先级,很明显RequestMappingHandlerMapping的order为0,是最高的,也就是如果一个uri进行,RequestMappingHandlerMapping能匹配,那么就肯定会由他来处理。

我们先来看看RequestMappingHandlerMapping的初始化过程吧。

  • RequestMappingHandlerMapping的初始化

我们先看看他的继承链

RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping {
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {

注意,他的父类实现了一个特殊的接口:InitializingBean

实现了这个接口的类会在这个Bean注入到Spring的时候调用afterPropertiesSet方法(这个很明显是InitializingBean定义的方法)。

那么调用这个方法的时机是什么呢?

那么这个就要回溯到我们讲解实例化Bean的那篇文章啦,也就是这个系列的第一篇文章。

找到AbstractAutowireCapableBeanFactory的doCreateBean方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

//..省去相对无关紧要的代码
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);//注入属性
            if (exposedObject != null) {
              //就是在这里执行了afterPropertiesSet和initMethod等方法
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }


        return exposedObject;
    }

我们要重点关注的是initializeBean方法

initializeBean

    protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Object run() {
                            //执行实现了Aware的接口的指定子接口的类的相应方法

                    invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
          //执行实现了Aware的接口的指定子接口的类的相应方法
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
          //对实现了BeanPostProcessor接口的类做相应处理,后面会讲到
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
          //执行afterPropertiesSet和initMethod方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }

        if (mbd == null || !mbd.isSynthetic()) {
                  //对实现了BeanPostProcessor接口的类做相应处理,后面会讲到

            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }
 
  

我们先重点关心invokeInitMethods,在这里执行了afterPropertiesSet

invokeInitMethods

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction() {
                        @Override
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null) {
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
 
  

方法很简单,就不多做说明了。注意afterPropertiesSet比init-method先执行。

好了,很明显,我们接下来就是要看下他的afterPropertiesSet到底做了什么。

都是在父类AbstractHandlerMethodMapping实现

    @Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }
    protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
    //得到所有注入到Spring容器中的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) &&
                    isHandler(getApplicationContext().getType(beanName))){
                detectHandlerMethods(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

1.得到所有注入到Spring容器中的Bean的beanName

2.筛选出符合条件的Bean(带有@Controller和@RequestMapping注解的Bean),并且将他们注入到

。。。。

我们先稍微看下是如何筛选的

    if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
                    isHandler(getApplicationContext().getType(beanName))){
                detectHandlerMethods(beanName);
            }
//RequestMappingHandlerMapping
    @Override
    protected boolean isHandler(Class beanType) {
        return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
                (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
    }

isHandler是在祖先父类AbstractHandlerMethodMapping\中定义的,实现是在RequestMappingHandlerMapping中,终于有件事是自己干了。很简单就是看这个bean到底有没有这两个注解。

得到符合条件的bean之后,我们调用detectHandlerMethods(beanName);来注册。

AbstractHandlerMethodMapping\

/** * Look for handler methods in a handler. * @param handler the bean name of a handler or a handler instance */
    protected void detectHandlerMethods(final Object handler) {
        Class handlerType =
                (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

        // Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances
        final Map mappings = new IdentityHashMap();
        final Class userType = ClassUtils.getUserClass(handlerType);

        Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
            @Override
            public boolean matches(Method method) {
                T mapping = getMappingForMethod(method, userType);
                if (mapping != null) {
                    mappings.put(method, mapping);
                    return true;
                }
                else {
                    return false;
                }
            }
        });

        for (Method method : methods) {
            registerHandlerMethod(handler, method, mappings.get(method));
        }
    }

1.对Bean中的所有方法进行筛选,对有@RequestMapping注解的Method进行处理。

2.将方法注册到HandlerMethod中,并最后与AbstractHandlerMapping这个基类的urlMap属性关联起来。

我们先来看看怎么筛选的。

Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
            @Override
            public boolean matches(Method method) {
                T mapping = getMappingForMethod(method, userType);
                if (mapping != null) {
                    mappings.put(method, mapping);
                    return true;
                }
                else {
                    return false;
                }
            }
        });
@Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) {
        RequestMappingInfo info = null;
        RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
        if (methodAnnotation != null) {
            RequestCondition methodCondition = getCustomMethodCondition(method);
            info = createRequestMappingInfo(methodAnnotation, methodCondition);
            RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
            if (typeAnnotation != null) {
                RequestCondition typeCondition = getCustomTypeCondition(handlerType);
                info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
            }
        }
        return info;
    }

终于有出现了久违的回调方法了,这里采用了回调方法来过滤方法。

getMappingForMethod的具体实现是在RequestMappingHandlerMapping,他终于又自己动了。

方法不难理解。

1.先找出带有@RequestMapping注解的方法,然后创建一个RequestMappingInfo实例,将@RequestMapping注解上的相关信息都注入到这个实例中。

2.如果这个bean上也有@RequestMapping注解,则将这两个@RequestMapping注解上的相关信息结合在一起,注入到一个RequestMappingInfo实例中,然后返回,方法上没有@RequestMapping注解则返回null,即被过滤掉。

接着就是注册了。

registerHandlerMethod

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
      //创建一个HandlerMethod实例
        HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
        HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
        if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
            throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
                    "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
                    oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
        }

        this.handlerMethods.put(mapping, newHandlerMethod);
        if (logger.isInfoEnabled()) {
            logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
        }

        Set patterns = getMappingPathPatterns(mapping);
        for (String pattern : patterns) {
            if (!getPathMatcher().isPattern(pattern)) {
                this.urlMap.add(pattern, mapping);
            }
        }

        if (this.namingStrategy != null) {
            String name = this.namingStrategy.getName(newHandlerMethod, mapping);
            updateNameMap(name, newHandlerMethod);
        }
    }

1.创建一个HandlerMethod实例,然后查看是否已经有相同的实例被创建了,如果有,则报错。

2.将新建的实例加入到handlerMethods属性中,以mapping为key。

3.使用getMappingPathPatterns得到mapping(这里即为RequestMappingInfo实例)的信息所匹配的uri pattern。

4.然后以pattern为key,mapping为value注入到AbstractHandlerMapping的urlMap属性中,这样一来就成功建立了urlMap与HandlerMethod的关系了。

好了,这个类的初始化就讲到这里了。

getHandler

接下来就看RequestMappingHandlerMapping的getHandler方法是怎么得到handler的。

getHandler方法只有在基类AbstractHandlerMapping中实现。

@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        return getHandlerExecutionChain(handler, request);
    }

而这个方法里面最重要的方法getHandlerInternal(request);是个模板方法。

显然是需要子类自己去实现的,这里的实现是在AbstractHandlerMethodMapping\中。

    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
      //将request关于请求路径的信息提取出来
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
      //根据请求uri 对应urlMap中的信息找到相应的HandlerMethod.
        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);
    }

其实讲完了怎么注册就不用再多讲怎么取了,因为就是在注册的Map中拿数据出来。

得到了Handler之后呢,我们就来到了。

            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

我们在前面讲注册handlerAdapters的时候说过,他们的order都是同样的,但是每一个支持的Handler类型都不一样,这里得到的就是RequestMappingHandlerAdapter。对应的supports方法:

AbstractHandlerMethodAdapter

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

得到相应的HandlerAdapter之后,会执行

                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这就是真正处理请求的方法。

AbstractHandlerMethodAdapter

    @Override
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return handleInternal(request, response, (HandlerMethod) handler);
    }
//RequestMappingHandlerAdapter
@Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandleMethod(request, response, handlerMethod);
                }
            }
        }

        return invokeHandleMethod(request, response, handlerMethod);
    }

RequestMappingHandlerAdapter的handleInternal对请求进行正式处理。

至于具体的处理请求过程,是非常复杂的,我们下次再细讲。

你可能感兴趣的:(springmvc)