Spring MVC 收集Controller

EnableWebMvc

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

EnableWebMvc上使用@Import导入了类DelegatingWebMvcConfiguration,含义为在容器扫描bean时,会将导入的类一起处理。
导入的DelegatingWebMvcConfiguration与父类WebMvcConfigurationSupport

DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
WebMvcConfigurationSupport
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping();
        handlerMapping.setOrder(0);
        handlerMapping.setInterceptors(getInterceptors());
        handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
        handlerMapping.setCorsConfigurations(getCorsConfigurations());

        PathMatchConfigurer configurer = getPathMatchConfigurer();
        if (configurer.isUseSuffixPatternMatch() != null) {
            handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch());
        }
        if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
            handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch());
        }
        if (configurer.isUseTrailingSlashMatch() != null) {
            handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
        }
        UrlPathHelper pathHelper = configurer.getUrlPathHelper();
        if (pathHelper != null) {
            handlerMapping.setUrlPathHelper(pathHelper);
        }
        PathMatcher pathMatcher = configurer.getPathMatcher();
        if (pathMatcher != null) {
            handlerMapping.setPathMatcher(pathMatcher);
        }

        return handlerMapping;
    }

DelegatingWebMvcConfiguration上的注解@Configuration,说明其为完全配置类,从父类继承的requestMappingHandlerMapping方法上的注解@Bean,说明会将RequestMappingHandlerMapping托管给容器,beanName为方法名。

RequestMappingHandlerMapping关系图

RequestMappingHandlerMapping的基类实现了InitializingBean方法,在容器初始化该bean时,会执行其初始化方法afterPropertiesSet

RequestMappingHandlerMapping
    @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();
    }
...
    @Override
    protected boolean isHandler(Class beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

父类AbstractHandlerMethodMappingafterPropertiesSet方法

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)) {
                    detectHandlerMethods(beanName);
                }
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

从容器中获取了所有的Object类型的bean,意味着拿到了所有bean,遍历bean使用isHandler判断。拥有Controller注解或者RequestMapping注解的视为Handler,对HandlerdetectHandlerMethods方法内选出其内部可以处理请求的方法。

RequestMappingHandlerMapping
    @Override
    protected boolean isHandler(Class beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
AbstractHandlerMethodMapping
    protected void detectHandlerMethods(final Object handler) {
        Class handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        final Class userType = ClassUtils.getUserClass(handlerType);

        Map methods = MethodIntrospector.selectMethods(userType,
                new MethodIntrospector.MetadataLookup() {
                    @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 entry : methods.entrySet()) {
            Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
            T mapping = entry.getValue();
            registerHandlerMethod(handler, invocableMethod, mapping);
        }
    }

MethodIntrospectorselectMethods方法

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

        if (!Proxy.isProxyClass(targetType)) {
            handlerTypes.add(targetType);
            specificHandlerType = targetType;
        }
        handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));

        for (Class currentHandlerType : handlerTypes) {
            final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

            ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method 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;
    }

获取当前处理的bean和其接口类,对他们的所有方法,在inspect中做处理,最终的处理在getMappingForMethod方法中

RequestMappingHandlerMapping
    @Override
    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;
    }

可以看到传入的参数为当前正在处理的方法和类,先获取方法的RequestMappingInfo,如果不为null再获取类的RequestMappingInfo,然后将方法与类的RequestMappingInfo相连接,构成最终的RequestMappingInfo。(例如方法上的mapping为/method,类上的mapping为/controller,那么最终的请求路径为/controller/method)

RequestMappingHandlerMapping
    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注解,再判断当前处理的是method还是class,最终创建RequestMappingInfo

回到AbstractHandlerMethodMappingdetectHandlerMethods方法中,MethodIntrospector.selectMethods方法执行完成之后的返回值是一个Map,包含所有能处理请求的方法。registerHandlerMethod方法中对这些方法进行注册。

AbstractHandlerMethodMapping
    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        this.mappingRegistry.register(mapping, handler, method);
    }
内部类 MappingRegistry
        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);

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

可以看到将内部类MappingRegistry中,使用handlermethod创建了HandlerMethod,然后将其与RequestMappingInfo按照KV的形式保存在MapmappingLookup中。然后拿到mapping内的路径,按照url-mapping的形式保存在MultiValueMap(一个Key对应多个Value)urlLookup中。最后在Mapregistry中保存了RequestMappingInfoMappingRegistration的映射。
至此,RequestMappingHandlerMapping的初始化方法执行完成。

总结:

  • 声明注解@EnableWebMvc,会将注解上导入的类DelegatingWebMvcConfiguration托管给容器
  • DelegatingWebMvcConfiguration上声明了注解@Configuration表示其是一个完全配置类,拥有配置Bean的能力。
  • 它的父类WebMvcConfigurationSupport中使用@Bean标注了方法requestMappingHandlerMapping,表示想要将该方法的返回值托管给容器,最终将类RequestMappingHandlerMapping托管给容器。
  • 在容器初始化类RequestMappingHandlerMapping时,由于它的基类实现了接口InitializingBean,所以它的初始化方法afterPropertiesSet会被调用。
  • 最终在基类AbstractHandlerMethodMappingafterPropertiesSet方法中调用了initHandlerMethods方法。完成了对所有包含@Controller注解或者@RequestMapping注解的类的处理,将这些类中的带有@RequestMapping注解的方法与其类合并为完全的RequestMappingInfo,保存在AbstractHandlerMethodMapping的属性中。

你可能感兴趣的:(Spring MVC 收集Controller)