- 源码版本 Spring5.3.x,SpringBoot版本2.5.x
- 仅讨论 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()); } } // 视图解析器等, 暂略 }