本系列以上的文章,到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
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
工作组件;
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
是进行Spring WebFlux
配置最主要的类,它可以直接被导入引用,或者扩展覆盖定制之后被导入引用。上面的类DelegatingWebFluxConfiguration
就是WebFluxConfigurationSupport
的子类。WebFluxAutoConfiguration
对DelegatingWebFluxConfiguration
又定制了一层才导入引用。而注解@EnableWebFlux
则是直接导入引用DelegatingWebFluxConfiguration
。这一节我们看看WebFluxConfigurationSupport
都做了什么。
package org.springframework.web.reactive.config;
// 省略 import 行
/**
* The main class for Spring WebFlux configuration.
*
* 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.
* 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.
* 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.
* 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