本系列以上的文章,到Spring WebFlux 工作原理分析 - 2.应用启动过程–3.更新应用上下文为止,其实我们已经得到了一个启动完成处于服务状态的Reactive Web Server
。但是为了更深入了解其中的Reactive Web Server
,我们通过以下篇幅对其创建和启动过程做了详细的分析:
基于以上的分析,我们知道:
- 缺省
Spring WebFlux
所使用的Reactive Web Server
是一个基于Netty
的Web
服务器, - 所使用的
HttpHandler
由应用上下文方法ReactiveWebServerApplicationContext#getHttpHandler
所提供, - 真正被使用的
HttpHandler bean
组件其实由HttpHandlerAutoConfiguration
自动配置机制使用WebHttpHandlerBuilder
结合当前应用上下文定义;
但是我们也看到,通过WebHttpHandlerBuilder
构建HttpHandler bean
过程中使用到了很多来自容器的bean
组件 ,比如 :
WebHandler
(1)WebFilter
(0…N)WebExceptionHandler
(0…N)WebSessionManager
(0|1)ServerCodecConfigurer
(0|1)LocaleContextResolver
(0|1)ForwardedHeaderTransformer
(0|1)
这些组件又是从哪里来的呢 ?为了弄明白这一点,我们就有必要了解一下Spring WebFlux
工作组件的自动配置机制WebFluxAutoConfiguration
。
其实,WebFluxAutoConfiguration
是Spring Boot
关于Spring WebFlux
运行时工作组件的自动配置类。通过WebFluxAutoConfiguration
自身以及其引入的内嵌配置类,Spring Boot
加载了相应的配置参数,将各个工作组件作为bean
注册到容器,并将开发人员或者框架自身所提供的WebFluxConfigurer
配置应用到各个工作组件上。
源代码
源代码版本 :
spring-webflux-5.1.8.RELEASE
WebFluxAutoConfiguration
package org.springframework.boot.autoconfigure.web.reactive;
// 省略 import 行
@Configuration
// 仅在 Reactive Web 环境下生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
// 仅在类 WebFluxConfigurer 存在于 classpath 上时生效
@ConditionalOnClass(WebFluxConfigurer.class)
// 仅在容器中不存在类型为 WebFluxConfigurationSupport 的bean时生效
// 本系列文章的例子应用中,开发人员没有定义类型为 WebFluxConfigurationSupport 的 bean,
// 所以该条件成立
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
// 在指定的自动配置机制应用之后应用
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
ValidationAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {
// 定义 bean hiddenHttpMethodFilter,类型 OrderedHiddenHttpMethodFilter
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
// 仅在配置参数 spring.webflux.hiddenmethod.filter.enabled 不存在或者为 true 时生效
@ConditionalOnProperty(prefix = "spring.webflux.hiddenmethod.filter", name = "enabled", matchIfMissing = true)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
// 内嵌配置类
@Configuration
// 1. 加载前缀为`spring.resources`到`bean ResourceProperties`;
// 2. 加载前缀为`spring.webflux`到`bean WebFluxProperties`;
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
// 导入配置类 EnableWebFluxConfiguration
// 配置类 EnableWebFluxConfiguration 是当前自动配置类的内嵌类,实现在下面
@Import({ EnableWebFluxConfiguration.class })
// 注意该配置类实现了接口 WebFluxConfigurer,
// 导致它会被 EnableWebFluxConfiguration 用于配置 WebFlux 工作组件,
// 参考 EnableWebFluxConfiguration 基类 DelegatingWebFluxConfiguration 的方法 :
// 1. #setConfigurers , 会通过自动装配机制注入容器中所有的 WebFluxConfigurer, 这里就是
// WebFluxConfig 被引入的地方;
// 2. 基类DelegatingWebFluxConfiguration中其他各个 #addXXX,#configureXXX,#getXXX
// 模板方法实现会使用所引入的 WebFluxConfigurer 以配置各种 WebFlux 工作组件;
public static class WebFluxConfig implements WebFluxConfigurer {
private static final Log logger = LogFactory.getLog(WebFluxConfig.class);
//前缀为 spring.resources 的配置项,构造函数注入
private final ResourceProperties resourceProperties;
// 前缀为 spring.webflux 的配置项,构造函数注入
private final WebFluxProperties webFluxProperties;
// 容器,构造函数注入
private final ListableBeanFactory beanFactory;
// 请求处理器参数解析器,构造函数注入
private final ObjectProvider<HandlerMethodArgumentResolver> argumentResolvers;
private final ObjectProvider<CodecCustomizer> codecCustomizers;
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
// 视图解析器 , 构造函数注入
private final ObjectProvider<ViewResolver> viewResolvers;
public WebFluxConfig(ResourceProperties resourceProperties, WebFluxProperties webFluxProperties,
ListableBeanFactory beanFactory, ObjectProvider<HandlerMethodArgumentResolver> resolvers,
ObjectProvider<CodecCustomizer> codecCustomizers,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizer,
ObjectProvider<ViewResolver> viewResolvers) {
this.resourceProperties = resourceProperties;
this.webFluxProperties = webFluxProperties;
this.beanFactory = beanFactory;
// 参数解析器
this.argumentResolvers = resolvers;
this.codecCustomizers = codecCustomizers;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizer.getIfAvailable();
this.viewResolvers = viewResolvers;
}
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.argumentResolvers.orderedStream().forEach(configurer::addCustomResolver);
}
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
this.codecCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configurer));
}
// 静态资源处理器配置
// /webjars/** => classpath:/META-INF/resources/webjars/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
// /webjars/** => classpath:/META-INF/resources/webjars/
if (!registry.hasMappingForPattern("/webjars/**")) {
ResourceHandlerRegistration registration = registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
configureResourceCaching(registration);
customizeResourceHandlerRegistration(registration);
}
// 根据配置参数决定是否要添加静态资源处理器 , 比如如下配置文件将会导致这里注册一项
// ResourceHandlerRegistration :
//
// spring :
// webflux :
// static-path-pattern : /static/**
// resources :
// static-locations : /tmp
//
String staticPathPattern = this.webFluxProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
ResourceHandlerRegistration registration = registry.addResourceHandler(staticPathPattern)
.addResourceLocations(this.resourceProperties.getStaticLocations());
configureResourceCaching(registration);
customizeResourceHandlerRegistration(registration);
}
}
private void configureResourceCaching(ResourceHandlerRegistration registration) {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
ResourceProperties.Cache.Cachecontrol cacheControl = this.resourceProperties.getCache().getCachecontrol();
if (cachePeriod != null && cacheControl.getMaxAge() == null) {
cacheControl.setMaxAge(cachePeriod);
}
registration.setCacheControl(cacheControl.toHttpCacheControl());
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// 将当前配置器所发现的 viewResolvers 注册到 registry
this.viewResolvers.orderedStream().forEach(registry::viewResolver);
}
@Override
public void addFormatters(FormatterRegistry registry) {
// 从容器中获取如下类型所有的类型转换器添加到 registry :
// Converter, GenericConverter, Formatter
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
private <T> Collection<T> getBeansOfType(Class<T> type) {
return this.beanFactory.getBeansOfType(type).values();
}
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
}
// 内嵌配置类,
// 1. 继承自 DelegatingWebFluxConfiguration,以应用容器中的各个 WebFluxConfigurer(比如上面的 WebFluxConfig)
// 2. 继承自 WebFluxConfigurationSupport, 以应用缺省的 WebFlux 组件配置逻辑,主要是定义各个组件bean
// 使用此配置类相当于使用了注解 @EnableWebFlux, 因为注解 @EnableWebFlux 其实是直接导入了
// DelegatingWebFluxConfiguration : @Import(DelegatingWebFluxConfiguration.class) ,
// 而 EnableWebFluxConfiguration 则是继承自 DelegatingWebFluxConfiguration 并做了一些扩展定制,
// 上面的 WebFluxConfig 就会导入该类
/**
* Configuration equivalent to {@code @EnableWebFlux}.
*/
@Configuration
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
private final WebFluxProperties webFluxProperties;
private final WebFluxRegistrations webFluxRegistrations;
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
this.webFluxProperties = webFluxProperties;
this.webFluxRegistrations = webFluxRegistrations.getIfUnique();
}
// 覆盖定义 bean webFluxConversionService,考虑到了配置文件属性中设置的日期格式
@Bean
@Override
public FormattingConversionService webFluxConversionService() {
WebConversionService conversionService = new WebConversionService(this.webFluxProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
// 覆盖定义 bean webFluxValidator
@Bean
@Override
public Validator webFluxValidator() {
if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
return super.webFluxValidator();
}
return ValidatorAdapter.get(getApplicationContext(), getValidator());
}
// 覆盖定义基类方法 createRequestMappingHandlerAdapter,
// 优先使用 webFluxRegistrations 配置,如果无 webFluxRegistrations 配置,使用基类缺省逻辑
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.webFluxRegistrations != null
&& this.webFluxRegistrations.getRequestMappingHandlerAdapter() != null) {
return this.webFluxRegistrations.getRequestMappingHandlerAdapter();
}
return super.createRequestMappingHandlerAdapter();
}
// 覆盖定义基类方法 RequestMappingHandlerMapping,
// 优先使用 webFluxRegistrations 配置,如果无 webFluxRegistrations 配置,使用基类缺省逻辑
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if (this.webFluxRegistrations != null
&& this.webFluxRegistrations.getRequestMappingHandlerMapping() != null) {
return this.webFluxRegistrations.getRequestMappingHandlerMapping();
}
return super.createRequestMappingHandlerMapping();
}
}
@Configuration
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
@Bean
public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
}
}
}
从上面的代码可见,WebFluxAutoConfiguration
在条件满足的情况下,主要做了如下事情 :
- 定义
WebFilter bean
:OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter
; - 定义内部配置类
WebFluxConfig
,实现自接口WebFluxConfigurer
; - 定义内部配置类
EnableWebFluxConfiguration
,继承自DelegatingWebFluxConfiguration
,以应用各个WebFluxConfigurer
和定义工作组件bean
; - 通过内部配置类
WebFluxConfig
导入EnableWebFluxConfiguration
,相当于触发自身这个WebFluxConfigurer
的应用,以及工作组件的定义;
这一动作相当于使用了注解
@EnableWebFlux
,只不过EnableWebFluxConfiguration
比@EnableWebFlux
多了一些扩展定制。
接下来,我们看看EnableWebFluxConfiguration
的两个基类DelegatingWebFluxConfiguration
和WebFluxConfigurationSupport
,它们是EnableWebFluxConfiguration
完成任务的主要类,分别负责 :
DelegatingWebFluxConfiguration
– 获取容器中的各个WebFluxConfigurer
以便配置WebFlux
工作组件;WebFluxConfigurationSupport
– 提供子类可以覆盖i的模板方法,并定义各种WebFlux
工作组件;
DelegatingWebFluxConfiguration
package org.springframework.web.reactive.config;
// 省略 import 行
/**
* A subclass of {@code WebFluxConfigurationSupport} that detects and delegates
* to all beans of type {@link WebFluxConfigurer} allowing them to customize the
* configuration provided by {@code WebFluxConfigurationSupport}. This is the
* class actually imported by {@link EnableWebFlux @EnableWebFlux}.
*
* @author Brian Clozel
* @since 5.0
*/
@Configuration
public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport {
// 一个 WebFluxConfigurerComposite 是多个 WebFluxConfigurer 的组合
private final WebFluxConfigurerComposite configurers = new WebFluxConfigurerComposite();
// 自动装配,容器中所有的 WebFluxConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebFluxConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebFluxConfigurers(configurers);
}
}
// 应用各个 WebFluxConfigurer#configureContentTypeResolver 到 RequestedContentTypeResolverBuilder builder
@Override
protected void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
this.configurers.configureContentTypeResolver(builder);
}
// 应用各个 WebFluxConfigurer#addCorsMappings 到 CorsRegistry registry
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
// 应用各个 WebFluxConfigurer#configurePathMatching 到 PathMatchConfigurer configurer
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
this.configurers.configurePathMatching(configurer);
}
// 应用各个 WebFluxConfigurer#addResourceHandlers 到 ResourceHandlerRegistry registry
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
// 应用各个 WebFluxConfigurer#configureArgumentResolvers 到 ArgumentResolverConfigurer configurer
@Override
protected void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.configurers.configureArgumentResolvers(configurer);
}
// 应用各个 WebFluxConfigurer#configureHttpMessageCodecs 到 ServerCodecConfigurer configurer
@Override
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
this.configurers.configureHttpMessageCodecs(configurer);
}
// 应用各个 WebFluxConfigurer#addFormatters 到 FormatterRegistry registry
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
// 覆盖基类方法,优先使用各个 WebFluxConfigurer 定义的 Validator
@Override
protected Validator getValidator() {
Validator validator = this.configurers.getValidator();
return (validator != null ? validator : super.getValidator());
}
// 覆盖基类方法,优先使用各个 WebFluxConfigurer 定义的 MessageCodesResolver
@Override
protected MessageCodesResolver getMessageCodesResolver() {
MessageCodesResolver messageCodesResolver = this.configurers.getMessageCodesResolver();
return (messageCodesResolver != null ? messageCodesResolver : super.getMessageCodesResolver());
}
// 应用各个 WebFluxConfigurer#configureViewResolvers 到 ViewResolverRegistry registry
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
}
WebFluxConfigurationSupport
WebFluxConfigurationSupport
是进行Spring WebFlux
配置最主要的类,它可以直接被导入引用,或者扩展覆盖定制之后被导入引用。上面的类DelegatingWebFluxConfiguration
就是WebFluxConfigurationSupport
的子类。WebFluxAutoConfiguration
对DelegatingWebFluxConfiguration
又定制了一层才导入引用。而注解@EnableWebFlux
则是直接导入引用DelegatingWebFluxConfiguration
。这一节我们看看WebFluxConfigurationSupport
都做了什么。
package org.springframework.web.reactive.config;
// 省略 import 行
/**
* The main class for Spring WebFlux configuration.
*
* <p>Import directly or extend and override protected methods to customize.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
// 实现了接口 ApplicationContextAware, 表示其实例会被容器设置应用上下文属性
public class WebFluxConfigurationSupport implements ApplicationContextAware {
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
@Nullable
private ViewResolverRegistry viewResolverRegistry;
@Nullable
private ApplicationContext applicationContext;
// ApplicationContextAware 接口约定的设置应用上下文属性的方法
@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
if (applicationContext != null) {
Assert.state(!applicationContext.containsBean("mvcContentNegotiationManager"),
"The Java/XML config for Spring MVC and Spring WebFlux cannot both be enabled, " +
"e.g. via @EnableWebMvc and @EnableWebFlux, in the same application.");
}
}
@Nullable
public final ApplicationContext getApplicationContext() {
return this.applicationContext;
}
// 定义 bean DispatcherHandler webHandler
// DispatcherHandler 可以认为是 Spring WebFlux 最核心的请求处理组件了,可以类比
// Spring MVC 的 DispatcherServlet
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}
// 定义 bean WebExceptionHandler responseStatusExceptionHandler
// 缺省使用实现类 WebFluxResponseStatusExceptionHandler , 根据异常类型或者
// @ResponseStatus 注解信息获取 Http 状态码
@Bean
@Order(0)
public WebExceptionHandler responseStatusExceptionHandler() {
return new WebFluxResponseStatusExceptionHandler();
}
// 定义 bean RequestMappingHandlerMapping requestMappingHandlerMapping
// 该 bean 管理 url pattern 到 handler 之间的映射,
// 该方法主要是创建该bean自身和设置辅助工作组件,方法返回时bean中映射表为空
// RequestMappingHandlerMapping 实现了 InitializingBean 接口,
// 所以它在对象初始化时会收集容器中所有的使用了注解 @Controller 或者注解 @RequestMapping
// 的 handler 类中的控制器方法,形成 url pattern -- 控制器方法映射表
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setContentTypeResolver(webFluxContentTypeResolver());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useCaseSensitiveMatch != null) {
mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null) {
mapping.setPathPrefixes(pathPrefixes);
}
return mapping;
}
/**
* Override to plug a sub-class of {@link RequestMappingHandlerMapping}.
*/
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
// 定义 bean
@Bean
public RequestedContentTypeResolver webFluxContentTypeResolver() {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
configureContentTypeResolver(builder);
return builder.build();
}
/**
* Override to configure how the requested content type is resolved.
*/
protected void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
}
/**
* Callback for building the global CORS configuration. This method is final.
* Use {@link #addCorsMappings(CorsRegistry)} to customize the CORS conifg.
*/
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
/**
* Override this method to configure cross origin requests processing.
* @see CorsRegistry
*/
protected void addCorsMappings(CorsRegistry registry) {
}
/**
* Callback for building the {@link PathMatchConfigurer}. This method is
* final, use {@link #configurePathMatching} to customize path matching.
*/
protected final PathMatchConfigurer getPathMatchConfigurer() {
if (this.pathMatchConfigurer == null) {
this.pathMatchConfigurer = new PathMatchConfigurer();
configurePathMatching(this.pathMatchConfigurer);
}
return this.pathMatchConfigurer;
}
/**
* Override to configure path matching options.
*/
public void configurePathMatching(PathMatchConfigurer configurer) {
}
// 定义 bean RouterFunctionMapping routerFunctionMapping
// 这是一组基于 RouterFunction 的 url 到 handler 的映射关系,
// 这里的 handler 是一个 HandlerFunction
// RouterFunctionMapping 实现了 InitializingBean 接口,
// 所以它在对象初始化时会收集容器中所有的 RouterFunction
@Bean
public RouterFunctionMapping routerFunctionMapping() {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageReaders(serverCodecConfigurer().getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
/**
* Override to plug a sub-class of {@link RouterFunctionMapping}.
*/
protected RouterFunctionMapping createRouterFunctionMapping() {
return new RouterFunctionMapping();
}
/**
* Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
* resource handlers. To configure resource handling, override
* {@link #addResourceHandlers}.
*/
// 定义 bean HandlerMapping resourceHandlerMapping 管理静态资源映射
// 如果没有配置静态资源映射,实现类为 EmptyHandlerMapping,内部映射表为空
// 如果存在静态资源映射,实现类为 SimpleUrlHandlerMapping, 内部映射表不为空
@Bean
public HandlerMapping resourceHandlerMapping() {
ResourceLoader resourceLoader = this.applicationContext;
if (resourceLoader == null) {
resourceLoader = new DefaultResourceLoader();
}
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
registry.setResourceUrlProvider(resourceUrlProvider());
addResourceHandlers(registry);
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
if (handlerMapping != null) {
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useTrailingSlashMatch != null) {
handlerMapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (useCaseSensitiveMatch != null) {
handlerMapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
}
else {
handlerMapping = new EmptyHandlerMapping();
}
return handlerMapping;
}
// 定义 bean
@Bean
public ResourceUrlProvider resourceUrlProvider() {
return new ResourceUrlProvider();
}
/**
* Override this method to add resource handlers for serving static resources.
* @see ResourceHandlerRegistry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 定义 bean
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setMessageReaders(serverCodecConfigurer().getReaders());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry());
ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
configureArgumentResolvers(configurer);
adapter.setArgumentResolverConfigurer(configurer);
return adapter;
}
/**
* Override to plug a sub-class of {@link RequestMappingHandlerAdapter}.
*/
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
return new RequestMappingHandlerAdapter();
}
/**
* Configure resolvers for custom controller method arguments.
*/
protected void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
}
/**
* Return the configurer for HTTP message readers and writers.
* <p>Use {@link #configureHttpMessageCodecs(ServerCodecConfigurer)} to
* configure the readers and writers.
*/
@Bean
public ServerCodecConfigurer serverCodecConfigurer() {
ServerCodecConfigurer serverCodecConfigurer = ServerCodecConfigurer.create();
configureHttpMessageCodecs(serverCodecConfigurer);
return serverCodecConfigurer;
}
/**
* Override to plug a sub-class of {@link LocaleContextResolver}.
*/
protected LocaleContextResolver createLocaleContextResolver() {
return new AcceptHeaderLocaleContextResolver();
}
@Bean
public LocaleContextResolver localeContextResolver() {
return createLocaleContextResolver();
}
/**
* Override to configure the HTTP message readers and writers to use.
*/
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
}
/**
* Return the {@link ConfigurableWebBindingInitializer} to use for
* initializing all {@link WebDataBinder} instances.
*/
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(webFluxConversionService());
initializer.setValidator(webFluxValidator());
MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
if (messageCodesResolver != null) {
initializer.setMessageCodesResolver(messageCodesResolver);
}
return initializer;
}
/**
* Return a {@link FormattingConversionService} for use with annotated controllers.
* <p>See {@link #addFormatters} as an alternative to overriding this method.
*/
@Bean
public FormattingConversionService webFluxConversionService() {
FormattingConversionService service = new DefaultFormattingConversionService();
addFormatters(service);
return service;
}
/**
* Override this method to add custom {@link Converter} and/or {@link Formatter}
* delegates to the common {@link FormattingConversionService}.
* @see #webFluxConversionService()
*/
protected void addFormatters(FormatterRegistry registry) {
}
/**
* Return a {@link ReactiveAdapterRegistry} to adapting reactive types.
*/
@Bean
public ReactiveAdapterRegistry webFluxAdapterRegistry() {
return new ReactiveAdapterRegistry();
}
/**
* Return a global {@link Validator} instance for example for validating
* {@code @RequestBody} method arguments.
* <p>Delegates to {@link #getValidator()} first. If that returns {@code null}
* checks the classpath for the presence of a JSR-303 implementations
* before creating a {@code OptionalValidatorFactoryBean}. If a JSR-303
* implementation is not available, a "no-op" {@link Validator} is returned.
*/
// 定义 bean
@Bean
public Validator webFluxValidator() {
Validator validator = getValidator();
if (validator == null) {
if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
Class<?> clazz;
try {
String name = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
clazz = ClassUtils.forName(name, getClass().getClassLoader());
}
catch (ClassNotFoundException | LinkageError ex) {
throw new BeanInitializationException("Failed to resolve default validator class", ex);
}
validator = (Validator) BeanUtils.instantiateClass(clazz);
}
else {
validator = new NoOpValidator();
}
}
return validator;
}
/**
* Override this method to provide a custom {@link Validator}.
*/
@Nullable
protected Validator getValidator() {
return null;
}
/**
* Override this method to provide a custom {@link MessageCodesResolver}.
*/
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
// 定义 bean
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return new HandlerFunctionAdapter();
}
// 定义 bean
@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return new SimpleHandlerAdapter();
}
// 定义 bean
@Bean
public ResponseEntityResultHandler responseEntityResultHandler() {
return new ResponseEntityResultHandler(serverCodecConfigurer().getWriters(),
webFluxContentTypeResolver(), webFluxAdapterRegistry());
}
// 定义 bean
@Bean
public ResponseBodyResultHandler responseBodyResultHandler() {
return new ResponseBodyResultHandler(serverCodecConfigurer().getWriters(),
webFluxContentTypeResolver(), webFluxAdapterRegistry());
}
// 定义 bean
@Bean
public ViewResolutionResultHandler viewResolutionResultHandler() {
ViewResolverRegistry registry = getViewResolverRegistry();
List<ViewResolver> resolvers = registry.getViewResolvers();
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(
resolvers, webFluxContentTypeResolver(), webFluxAdapterRegistry());
handler.setDefaultViews(registry.getDefaultViews());
handler.setOrder(registry.getOrder());
return handler;
}
// 定义 bean
@Bean
public ServerResponseResultHandler serverResponseResultHandler() {
List<ViewResolver> resolvers = getViewResolverRegistry().getViewResolvers();
ServerResponseResultHandler handler = new ServerResponseResultHandler();
handler.setMessageWriters(serverCodecConfigurer().getWriters());
handler.setViewResolvers(resolvers);
return handler;
}
/**
* Callback for building the {@link ViewResolverRegistry}. This method is final,
* use {@link #configureViewResolvers} to customize view resolvers.
*/
protected final ViewResolverRegistry getViewResolverRegistry() {
if (this.viewResolverRegistry == null) {
this.viewResolverRegistry = new ViewResolverRegistry(this.applicationContext);
configureViewResolvers(this.viewResolverRegistry);
}
return this.viewResolverRegistry;
}
/**
* Configure view resolution for supporting template engines.
* @see ViewResolverRegistry
*/
protected void configureViewResolvers(ViewResolverRegistry registry) {
}
private static final class EmptyHandlerMapping extends AbstractHandlerMapping {
@Override
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
return Mono.empty();
}
}
private static final class NoOpValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(@Nullable Object target, Errors errors) {
}
}
}
总结
从上面的代码可见,WebFluxAutoConfiguration
的主要任务如下 :
- 定义
bean OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter
- 引入配置类
WebFluxConfig
(实现了接口WebFluxConfigurer
)- 加载前缀为
spring.resources
到bean ResourceProperties
; - 加载前缀为
spring.webflux
到bean WebFluxProperties
; - 引入配置类
EnableWebFluxConfiguration
- 继承自
DelegatingWebFluxConfiguration
- 应用容器中的各个
WebFluxConfigurer
- 应用容器中的各个
- 定义
bean FormattingConversionService webFluxConversionService
- 实现类为
DefaultFormattingConversionService
- 实现类为
- 定义
bean Validator webFluxValidator
- 继承自
WebFluxConfigurationSupport
- 定义
bean DispatcherHandler webHandler
- 实现了接口
WebHandler
- 实现了接口
- 定义
bean WebExceptionHandler responseStatusExceptionHandler
- 实现类为
WebFluxResponseStatusExceptionHandler
- 实现类为
- 定义
bean RequestMappingHandlerMapping requestMappingHandlerMapping
- 定义
bean RequestedContentTypeResolver webFluxContentTypeResolver
- 定义
bean RouterFunctionMapping routerFunctionMapping
- 定义
bean HandlerMapping resourceHandlerMapping
- 定义
bean ResourceUrlProvider resourceUrlProvider
- 定义
bean RequestMappingHandlerAdapter requestMappingHandlerAdapter
- 定义
bean ServerCodecConfigurer serverCodecConfigurer
- 定义
bean LocaleContextResolver localeContextResolver
- 实现类为
AcceptHeaderLocaleContextResolver
- 实现类为
- 定义
bean ReactiveAdapterRegistry webFluxAdapterRegistry
- 定义
bean HandlerFunctionAdapter handlerFunctionAdapter
- 定义
bean SimpleHandlerAdapter simpleHandlerAdapter
- 定义
bean ResponseEntityResultHandler responseEntityResultHandler
- 定义
bean ResponseBodyResultHandler responseBodyResultHandler
- 定义
bean ViewResolutionResultHandler viewResolutionResultHandler
- 定义
bean ServerResponseResultHandler serverResponseResultHandler
- 定义
- 继承自
- 引入配置类
ResourceChainCustomizerConfiguration
- 定义
bean ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer
- 定义
- 加载前缀为