处理器映射器HandlerMapping

  1. 源码版本 Spring5.3.x,SpringBoot版本2.5.x
  2. 仅讨论 RequestMappingHandlerMapping 这个处理注解的处理器映射器

 

一、自动配置

既然使用了SpringBoot,SpringMVC相关的东西肯定是被自动配置了的

1. WebMvcAutoConfiguration 

大致是 SpringMVC 最顶层/最开始的一个自动配置

@Configuration(proxyBeanMethods = false)
// 要求是 Servlet 项目, 其他项目没使用过, 暂时仅使用过 Servlet 项目
@ConditionalOnWebApplication(type = Type.SERVLET)
// Servlet 相关的类, DispatcherServlet 前端控制器, WebMvcConfigurer Mvc相关配置器
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 通过名称就知道是与Mvc配置(WebMvcConfigurer)相关的
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
// 几个自动配置类, DispatcherServlet 自动配置的、线程池自动配置的、校验器自动配置的
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration { }

 

下面是 RequestHandlerHanderMapping 的注入

public class WebMvcAutoConfiguration {
    @Configuration(proxyBeanMethods = false)
    // WebMVC 的配置
    【@Import(EnableWebMvcConfiguration.class)】
    @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware { }
    
    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(WebProperties.class)
    【父类 DelegatingWebMvcConfiguration 是 SpringWeb 的, 不是 SpringBoot 的】
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        【RequestMappingHandlerMapping 处理器映射器】
        @Bean
        @Primary
        @Override
        public RequestMappingHandlerMapping requestMappingHandlerMapping(
                // 下面的方法注入的, 判断请求MIME类型的
                @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
                // 类型转换器
                @Qualifier("mvcConversionService") FormattingConversionService conversionService,
                // 资源读取
                // WebMvcConfigurationSupport#mvcResourceUrlProvider @Bean 注入
                @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
            // Must be @Primary for MvcUriComponentsBuilder to work
            // SpringWeb 的, 显然 RequestMappingHandlerMapping 在 Web 时代就有了
            return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
                    resourceUrlProvider);
        }
        
        
        // 下面两个后续再详解
        @Bean
        @Override
        @SuppressWarnings("deprecation")
        public ContentNegotiationManager mvcContentNegotiationManager() { }
        
        // 类型转换器, WebConversionService 是 SpringBoot 自己的, 替换了如 @EnableWebMvc/@EnableWebFlux 提供的类型, 与它们不同
        // 后续再详解
        @Bean
        @Override
        public FormattingConversionService mvcConversionService() {}
    }
}

 

 

EnableWebMvcConfiguration  是配置 Web 项目的各种配置的,继承了 DelegatingWebMvcConfiguration 

看下 SpringBoot 前就存在的注解 @EnableWebMvc

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { }

可以看出 DelegatingWebMvcConfiguration 是对 SpringWebMvc 的各种配置,而 SpringBoot 的 EnableWebMvcConfiguration  在此基础上进一步的处理了,替换了一些原有的 Bean

DelegatingWebMvcConfiguration 略一下,可以看出主要是处理我们自定义的 WebMvcConfigurer

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();


    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
}
class WebMvcConfigurerComposite implements WebMvcConfigurer {
    private final List<WebMvcConfigurer> delegates = new ArrayList<>();
}

 

二、创建

 

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        // protected的, 可以再次看 EnableWebMvcConfiguration 的实现, 它的实现是看有没有唯一的 WebMvcRegistrations 被注入(构造函数使用 ObjectProvider 注入)
        //    有就再看它提供了 RequestMappingHandlerMapping, 没有则执行 super 的也就是当前类的, 当前类 new
        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        // 拦截器, 注入了两个, 都是preHandle时设置 Request 域属性的为其实例的(conversionService、resourceUrlProvider)
        mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
        // 请求类型解析
        mapping.setContentNegotiationManager(contentNegotiationManager);
        // 跨域处理, protected的 , SpringBoot 没有处理, 也就是默认啥也没有
        mapping.setCorsConfigurations(getCorsConfigurations());
        // 路径匹配, 可以看到无论是 SpringBoot 的 EnableWebMvcConfiguration 还是当前类的 requestMappingHandlerMapping 都要求注入一个 resourceUrlProvider
        //  实际当前类就使用 @Bean 注入了, 因此这里面就是它自己注入的, SpringBoot 也没有进行特殊处理
        PathMatchConfigurer pathConfig = getPathMatchConfigurer();
        if (pathConfig.getPatternParser() != null) {
            mapping.setPatternParser(pathConfig.getPatternParser());
        }
        else {
            mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
            mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
            // 下面略, 这个版本都弃用了
        }
        
        // 默认 true, 末尾斜杠匹配, /xxx/xx ==> /xxx/xx/
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }

        return mapping;
    }
    
    protected final Object[] getInterceptors(
            FormattingConversionService mvcConversionService,
            ResourceUrlProvider mvcResourceUrlProvider) {

        if (this.interceptors == null) {
            InterceptorRegistry registry = new InterceptorRegistry();
            // 我们自定义的拦截器在这里处理, 调用子类进行处理  DelegatingWebMvcConfiguration
            // 子类 DelegatingWebMvcConfiguration 通过 @Autowired 注入了所有 WebMvcConfigurer
            // 当 addInterceptors 时, 所有 WebMvcConfigurer 都被调用注入数据
            addInterceptors(registry);
            registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
            registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
            this.interceptors = registry.getInterceptors();
        }
        return this.interceptors.toArray();
    }
}

 

 

三、收集 Controller

RequestMappingHandlerMapping:继承 HandlerMapping 表示是一个处理器映射器,继承 InitializingBean 进行后续处理

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    
    public void afterPropertiesSet() {
        initHandlerMethods();
    }
    
    protected void initHandlerMethods() {
        // getCandidateBeanNames 就是考虑父子容器的问题吧, 这里暂略, 可认为是拿出所有 BeanName
        for (String beanName : getCandidateBeanNames()) {
            // 普通 Bean, 而非 @Scope的
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                // 这里查找所有 HandlerMethod
                processCandidateBean(beanName);
            }
        }
        // 略, 打印日志
        handlerMethodsInitialized(getHandlerMethods());
    }
    
    protected void processCandidateBean(String beanName) {
        Class<?> beanType = null;
        try {
            // 类型
            beanType = obtainApplicationContext().getType(beanName);
        }
        
        // isHandler: @Controller 或 @RequestMapping 注解
        if (beanType != null && isHandler(beanType)) {
            // 名称
            detectHandlerMethods(beanName);
        }
    }
    
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    
    protected void detectHandlerMethods(Object handler) {
        Class<?> handlerType = (
                // beanName
                handler instanceof String ?
                // 获取Bean类型
                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 {
                            // 外面略过, 这里实际就是@RequestMapping的类和方法配置信息解析并封装起来, 并根据GET、consumers等要求封装为 Condition 类便于处理
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            // mapping 就是解析后的 RequestMappingInfo, method是对应的Method
            methods.forEach((method, mapping) -> {
                // 可执行的 Method, userType 和 方法的 DeclaringClass 相同则它, 没有则所有接口, 再没有则 target
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                // 注册, 注意这里的 handler 只是 beanName
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }
    
    
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        // 根据 @RequestMapping 创建方法信息, 就是解析 @RequestMapping, 将方法和解析信息封装起来, 还有根据配置的各种要求条件添加 Condition
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            // 对类解析, 没有 @RequestMapping 的方法显然就没必要解析类了
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                // 绑定, 比如说 路径连起来啊等, 条件合并等
                info = typeInfo.combine(info);
            }
            // 略, 为null
            String prefix = getPathPrefix(handlerType);
            if (prefix != null) {
                info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
            }
        }
        return info;
    }
    
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        // 合并注解,也就是GetMapping使用了RequestMapping注解,那么使用GetMapping这个方法也可以解析出来
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        // 注: 内部两个都默认返回 null
        RequestCondition<?> condition = (
                element instanceof Class ?
                // 类级别条件
                getCustomTypeCondition((Class<?>) element) :
                // 方法条件
                getCustomMethodCondition((Method) element));
        // 创建
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }
    
    protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

        // 保存了方法信息和@RequestMapping信息
        RequestMappingInfo.Builder builder = RequestMappingInfo
                // requestMapping.path() 注解是被代理过的, 大致是获得 @RequestMapping配置的路径
                // 还没处理掉{}
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                // 请求方法
                .methods(requestMapping.method())
                // 参数要求
                .params(requestMapping.params())
                // 请求头要求
                .headers(requestMapping.headers())
                // contentType 要求
                .consumes(requestMapping.consumes())
                // accept 要求
                .produces(requestMapping.produces())
                //
                .mappingName(requestMapping.name());
        if (customCondition != null) {
            builder.customCondition(customCondition);
        }

        // build 会根据我们@RequestMapping配置的添加很多 Condition
        return builder.options(this.config).build();
    }
    
    public void registerMapping(T mapping, Object handler, Method method) {
        // 注意这里的 handler 只是 beanName
        this.mappingRegistry.register(mapping, handler, method);
    }
}

 

 

四、WebMvcConfigurer 于 WebMvcAutoConfigurationAdapter

WebMvcConfigurer 用于对 MVC 进行配置,如跨域、类型转换、拦截器、视图解析器、参数解析、返回值处理、MessageConverter、校验器等待\

WebMvcAutoConfigurationAdapter,注意它继承了 WebMvcConfigurer,也就是一个 WebMvc 配置,会被  WebMvcConfigurerComposite  注入

// MVC 的自动配置类
public class WebMvcAutoConfiguration {

    @Configuration(proxyBeanMethods = false)
    // MVC 配置, 上面的 RequestMappingHandlerMapping 就是它注入的
    @Import(EnableWebMvcConfiguration.class)
    @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {}

 

// MVC 的自动配置类
public class WebMvcAutoConfiguration {

    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
        // 通过构造函数可以看到, 就是收集所有(包括我们自定义)的一些配置
        // HttpMessageConverters
        // ServletRegistrationBean 这个是封装我们注入的 Servlet、Filter 等的
        // ?
        public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,
                ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
                ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
                ObjectProvider<DispatcherServletPath> dispatcherServletPath,
                ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = webProperties.getResources();
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
            this.dispatcherServletPath = dispatcherServletPath;
            this.servletRegistrations = servletRegistrations;
            this.mvcProperties.checkConfiguration();
        }

        @Override
        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }

        // 添加 HttpMessageConverter
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            this.messageConvertersProvider
                    .ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters()));
        }

        // 异步支持, 暂略
        @Override
        public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
            if (this.beanFactory.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {
                Object taskExecutor = this.beanFactory
                        .getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
                if (taskExecutor instanceof AsyncTaskExecutor) {
                    configurer.setTaskExecutor(((AsyncTaskExecutor) taskExecutor));
                }
            }
            Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();
            if (timeout != null) {
                configurer.setDefaultTimeout(timeout.toMillis());
            }
        }

        // 视图解析器等, 暂略
}

 

posted @ 2021-11-14 00:32  YangDanMua  阅读(316)  评论(0编辑  收藏  举报