• 处理器映射器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());
                }
            }
    
            // 视图解析器等, 暂略
    }
  • 相关阅读:
    Django搭建开发‘学习笔记’项目二(创建应用程序)
    Django搭建开发‘学习笔记’项目一(建立项目)
    WEB渗透 --- 常见问题总结
    ConstraintLayout使用手册
    Java源码分析(1):二分查找 + 循环递归实现
    小黄衫买家秀
    Android权限申请完全解析(一):Android自带的权限申请
    个人作业——软件工程实践总结作业
    beta阶段学习博客(一) js交互
    个人作业——软件产品案例分析
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15550452.html
Copyright © 2020-2023  润新知