根据之前的经验,咱使用WebFlux的时候,主启动类上相对比于WebMvc来讲没有任何区别,那只有自动配置类可以控制WebFlux的装配了,那装配的自动配置类不难猜想应该是:WebFluxAutoConfiguration
。
1. WebFluxAutoConfiguration
复制 @ Configuration
@ ConditionalOnWebApplication (type = ConditionalOnWebApplication . Type . REACTIVE )
@ ConditionalOnClass ( WebFluxConfigurer . class )
@ ConditionalOnMissingBean ({ WebFluxConfigurationSupport . class })
@ AutoConfigureAfter ({ ReactiveWebServerFactoryAutoConfiguration . class , CodecsAutoConfiguration . class ,
ValidationAutoConfiguration . class })
@ AutoConfigureOrder ( Ordered . HIGHEST_PRECEDENCE + 10 )
public class WebFluxAutoConfiguration
可以发现它跟 WebMvcAutoConfiguration 几乎没什么太大的区别:
复制 @ Configuration
@ ConditionalOnWebApplication (type = Type . SERVLET )
@ ConditionalOnClass ({ Servlet . class , DispatcherServlet . class , WebMvcConfigurer . class })
@ ConditionalOnMissingBean ( WebMvcConfigurationSupport . class )
@ AutoConfigureOrder ( Ordered . HIGHEST_PRECEDENCE + 10 )
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration . class })
public class WebMvcAutoConfiguration
只不过判断条件不太一样而已,WebFlux 需要判断的应用类型为 REACTIVE ,而 WebMvc 为 SERVLET ;WebFlux 需要判断classpath下是否有 WebFluxConfigurer
类,而 WebMvc 需要的是 Servlet
、DispatcherServlet
、WebMvcConfigurer
三个类。
根据之前读 WebMvc 的自动配置,肯定要先走进 ReactiveWebServerFactoryAutoConfiguration
,看一眼嵌入式容器的配置。
2. ReactiveWebServerFactoryAutoConfiguration
复制 @ AutoConfigureOrder ( Ordered . HIGHEST_PRECEDENCE )
@ Configuration
@ ConditionalOnClass ( ReactiveHttpInputMessage . class )
@ ConditionalOnWebApplication (type = ConditionalOnWebApplication . Type . REACTIVE )
@ EnableConfigurationProperties ( ServerProperties . class )
@ Import ({ ReactiveWebServerFactoryAutoConfiguration . BeanPostProcessorsRegistrar . class ,
ReactiveWebServerFactoryConfiguration . EmbeddedTomcat . class ,
ReactiveWebServerFactoryConfiguration . EmbeddedJetty . class ,
ReactiveWebServerFactoryConfiguration . EmbeddedUndertow . class ,
ReactiveWebServerFactoryConfiguration . EmbeddedNetty . class })
public class ReactiveWebServerFactoryAutoConfiguration
果不其然,它会导入嵌入式容器工厂的配置类。由于在默认情况下,导入 spring-boot-starter-webflux
,默认使用 Netty 作为嵌入式容器,故此处 EmbeddedNetty
生效,生效的原因与之前 WebMvc 原理一致,不再赘述。
看一眼 EmbeddedNetty
都干了什么:
2.1 EmbeddedNetty
复制 @ Configuration
@ ConditionalOnMissingBean ( ReactiveWebServerFactory . class )
@ ConditionalOnClass ({ HttpServer . class })
static class EmbeddedNetty {
@ Bean
@ ConditionalOnMissingBean
public ReactorResourceFactory reactorServerResourceFactory () {
return new ReactorResourceFactory() ;
}
@ Bean
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory ( ReactorResourceFactory resourceFactory) {
NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory() ;
serverFactory . setResourceFactory (resourceFactory);
return serverFactory;
}
}
很明显它创建了一个 ReactorResourceFactory
,一个 NettyReactiveWebServerFactory
。NettyReactiveWebServerFactory
从命名上看就知道它应该是类比于 WebMvc 中的 TomcatServletWebServerFactory
,那 ReactorResourceFactory
是什么呢?
2.2 ReactorResourceFactory
它的文档注释原文翻译:
Factory to manage Reactor Netty resources, i.e. LoopResources for event loop threads, and ConnectionProvider for the connection pool, within the lifecycle of a Spring ApplicationContext. This factory implements InitializingBean and DisposableBean and is expected typically to be declared as a Spring-managed bean.
在Spring ApplicationContext
的生命周期内,用于管理Reactor Netty资源的工厂,即用于事件循环线程的 LoopResources
和用于连接池的 ConnectionProvider
。
该工厂实现 InitializingBean
和 DisposableBean
,通常应将其声明为Spring管理的Bean。
划重点:管理Reactor Netty资源的工厂 ,这个说法怎么感觉跟线程池似的?而且后面还有循环、连接池的概念,难不成它就类比于jdbc中的 DataSource
?往里看它的成员:
复制 public class ReactorResourceFactory implements InitializingBean , DisposableBean {
private boolean useGlobalResources = true ;
private Consumer < HttpResources > globalResourcesConsumer;
private Supplier < ConnectionProvider > connectionProviderSupplier = () -> ConnectionProvider . elastic ( "webflux" );
private Supplier < LoopResources > loopResourcesSupplier = () -> LoopResources . create ( "webflux-http" );
// ......
注意第三个属性:connectionProviderSupplier
,它的创建方式是 ConnectionProvider.elastic
,突然感觉眼熟:前面看调度器的时候,对于 Reactor 的线程池就有一种 elastic 类型的!莫非它确实就是管理 ConnectionProvider
的?点开 ConnectionProvider 的 elastic 方法:
复制 static ConnectionProvider elastic( String name) {
return new PooledConnectionProvider(name ,
(bootstrap , handler , checker) -> new SimpleChannelPool(bootstrap ,
handler, checker, true, false));
果然它就是一个连接的提供者,而且它还是 Pool ,换句话说,咱就可以简单的理解成它是 Reactor Netty 的连接池 。
实际Debug了一下,发现确实与咱的推测基本贴合:
果然有关于池的好多属性,而且下面有 select 和 worker 的概念,这就是 Netty 的核心。(12是因为我用的笔记本CPU是i7-8750H,6核12线程,所以这里是12)
ReactiveWebServerFactoryAutoConfiguration
看完之后,回到 WebFluxAutoConfiguration
:
复制 @ AutoConfigureAfter ({ DispatcherServletAutoConfiguration . class , CodecsAutoConfiguration . class ,
ValidationAutoConfiguration . class })
public class WebMvcAutoConfiguration
它除了还要先处理 ValidationAutoConfiguration
的JSR-303 校验之外,还要先处理一个 CodecsAutoConfiguration
:
3. CodecsAutoConfiguration
可以发现这里面只是注册了一个 json 转换器,以及日志工具。源码很简单,不过多解析。
复制 @ Configuration
@ ConditionalOnClass ( CodecConfigurer . class )
@ AutoConfigureAfter ( JacksonAutoConfiguration . class )
public class CodecsAutoConfiguration {
private static final MimeType [] EMPTY_MIME_TYPES = {};
@ Configuration
@ ConditionalOnClass ( ObjectMapper . class )
static class JacksonCodecConfiguration {
@ Bean
@ Order ( 0 )
@ ConditionalOnBean ( ObjectMapper . class )
public CodecCustomizer jacksonCodecCustomizer ( ObjectMapper objectMapper) {
return (configurer) -> {
CodecConfigurer . DefaultCodecs defaults = configurer . defaultCodecs ();
defaults . jackson2JsonDecoder ( new Jackson2JsonDecoder(objectMapper , EMPTY_MIME_TYPES) );
defaults . jackson2JsonEncoder ( new Jackson2JsonEncoder(objectMapper , EMPTY_MIME_TYPES) );
};
}
}
@ Configuration
@ EnableConfigurationProperties ( HttpProperties . class )
static class LoggingCodecConfiguration {
@ Bean
@ Order ( 0 )
public CodecCustomizer loggingCodecCustomizer ( HttpProperties properties) {
return (configurer) -> configurer . defaultCodecs ()
. enableLoggingRequestDetails ( properties . isLogRequestDetails ());
}
}
}
接下来才是最核心的 WebFluxAutoConfiguration
。源码中它定义了三个内部类,咱一个一个来看:
4. WebFluxConfig
复制 @ Configuration
@ EnableConfigurationProperties ({ ResourceProperties . class , WebFluxProperties . class })
@ Import ({ EnableWebFluxConfiguration . class })
public static class WebFluxConfig implements WebFluxConfigurer
可以看到它又导入了一个 EnableWebFluxConfiguration
,而它就是下面第5章节的 EnableWebFluxConfiguration
,咱从上往下一样一样看。先看 WebFluxConfig
中的配置:
4.1 静态资源映射
复制 public void addResourceHandlers( ResourceHandlerRegistry registry) {
if ( ! this . resourceProperties . isAddMappings ()) {
logger . debug ( "Default resource handling disabled" );
return ;
}
if ( ! registry . hasMappingForPattern ( "/webjars/**" )) {
ResourceHandlerRegistration registration = registry . addResourceHandler ( "/webjars/**" )
. addResourceLocations ( "classpath:/META-INF/resources/webjars/" );
configureResourceCaching(registration) ;
customizeResourceHandlerRegistration(registration) ;
}
String staticPathPattern = this . webFluxProperties . getStaticPathPattern ();
if ( ! registry . hasMappingForPattern (staticPathPattern)) {
ResourceHandlerRegistration registration = registry . addResourceHandler (staticPathPattern)
. addResourceLocations ( this . resourceProperties . getStaticLocations ());
configureResourceCaching(registration) ;
customizeResourceHandlerRegistration(registration) ;
}
}
可以发现它处理的逻辑几乎跟 WebMvc 部分一致!也是处理 webjars 的资源,以及 ResourceProperties 中的静态路径,默认情况下:
复制 public class ResourceProperties {
private static final String [] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/" ,
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
private String [] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
发现也是跟 WebMvc 部分一样的路径。
4.2 ViewResolver
复制 public void configureViewResolvers( ViewResolverRegistry registry) {
this . viewResolvers . orderedStream () . forEach (registry :: viewResolver);
}
可以发现这部分是配置 ViewResolver
的,不过默认情况下Debug发现并没有进入 ViewResolverRegistry
的 registry
方法中,暂且略过。
4.3 Converter和Formatter
复制 public void addFormatters( FormatterRegistry registry) {
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);
}
}
这部分在 WebMvc 部分也是一模一样的,直接copy过来的!(不过这部分不是特别关键,而且之前也没有单独拿出来聊,小伙伴们知道这里是配置转换器的即可)
大概来看 WebFluxConfig
主要就配置了这几个组件,继续往下看:
5. EnableWebFluxConfiguration
先看一眼继承:
复制 @ Configuration
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration
它继承了 DelegatingWebFluxConfiguration
,这个套路貌似跟 WebMvc 部分也是一样的!
复制 @ Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware
至于这些 Delegating***Configuration
的作用咱之前也提到过,它就是 @EnableWebMvc
或者 @EnableWebFlux
注解导入的配置类:
复制 @ Import ( DelegatingWebFluxConfiguration . class )
public @ interface EnableWebFlux
它的作用小伙伴们还记得吗?只要在 SpringBoot 中标注了这样的注解,代表 SpringBoot 默认的自动配置类不生效,改由咱们自己接管配置 WebMvc 或者 WebFlux 。
下面来看它里面配置的组件:
5.1 FormattingConversionService
复制 @ Bean
public FormattingConversionService webFluxConversionService() {
WebConversionService conversionService = new WebConversionService( this . webFluxProperties . getDateFormat()) ;
addFormatters(conversionService) ;
return conversionService;
}
看这个类的名,大概也能联想到之前看 WebMvc 部分的那个参数类型转换器吧!而且代码几乎也一模一样。
5.2 Validator
复制 @ Bean
public Validator webFluxValidator() {
if ( ! ClassUtils . isPresent ( "javax.validation.Validator" , getClass() . getClassLoader ())) {
return super . webFluxValidator ();
}
return ValidatorAdapter . get ( getApplicationContext() , getValidator() );
}
很明显它是配置 JSR-303 参数校验的校验器。
5.3 HandlerMapping和HandlerAdapter
复制 protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if ( this . webFluxRegistrations != null
&& this . webFluxRegistrations . getRequestMappingHandlerAdapter () != null ) {
return this . webFluxRegistrations . getRequestMappingHandlerAdapter ();
}
return super . createRequestMappingHandlerAdapter ();
}
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if ( this . webFluxRegistrations != null
&& this . webFluxRegistrations . getRequestMappingHandlerMapping () != null ) {
return this . webFluxRegistrations . getRequestMappingHandlerMapping ();
}
return super . createRequestMappingHandlerMapping ();
}
哇塞这不是咱之前在 WebMvc 部分常聊的两个配合 DispatcherServlet
的核心组件吗?对的,它在 WebFlux 中也是一样的其效果。
6. WebFluxConfigurationSupport
上面咱注意到了 EnableWebFluxConfiguration
继承了 DelegatingWebFluxConfiguration
,而它又继承了 WebFluxConfigurationSupport
,这个配置类中还注册了一些组件:
6.1 DispatcherHandler
复制 @ Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler() ;
}
发现了 WebFlux 的核心前端控制器:**DispatcherHandler**
,它在这里注册了,而且比 DispatcherServlet
简单的多。
6.2 WebExceptionHandler
复制 @ Bean
@ Order ( 0 )
public WebExceptionHandler responseStatusExceptionHandler() {
return new WebFluxResponseStatusExceptionHandler() ;
}
WebFlux 的异常状态响应处理器,见名知意,不再深扒。
6.3 RequestMappingHandlerMapping
复制 @ 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;
}
可以发现这里真正创建了 RequestMappingHandlerMapping
组件。
6.4 RouterFunctionMapping
复制 @ Bean
public RouterFunctionMapping routerFunctionMapping() {
RouterFunctionMapping mapping = createRouterFunctionMapping() ;
mapping . setOrder ( - 1 ); // go before RequestMappingHandlerMapping
mapping . setMessageReaders ( serverCodecConfigurer() . getReaders ());
mapping . setCorsConfigurations ( getCorsConfigurations() );
return mapping;
}
与 RequestMappingHandlerMapping
区别开来,它是函数式端点路由编程的Mapping处理器 。至于它的作用,咱到第33篇再聊。
6.5 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;
}
注意看源码中第一个if结构下面,它用了一个 ResourceHandlerRegistry
,有没有感觉似曾相识?咱在前面看静态资源映射的时候见过它,它是处理静态资源的映射 的。通常情况下咱的项目中会有一些静态资源,只要存在静态资源,它就会创建一个 SimpleUrlHandlerMapping
来真正处理静态资源的路径映射。通过Debug,发现确实存在(因为有应用图标 favicon.ico
):
6.6 RequestMappingHandlerAdapter
复制 @ 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;
}
这里真正创建了 RequestMappingHandlerAdapter
。
6.7 LocaleContextResolver
复制 @ Bean
public LocaleContextResolver localeContextResolver() {
return createLocaleContextResolver() ;
}
这个 LocaleContextResolver
组件从类名上就可以看出来它是与国际化相关的组件。
6.8 ReactiveAdapterRegistry
复制 @ Bean
public ReactiveAdapterRegistry webFluxAdapterRegistry() {
return new ReactiveAdapterRegistry() ;
}
这个 ReactiveAdapterRegistry
类看上去应该是处理 Reactive 类型的,看一眼它的文档注释:
A registry of adapters to adapt Reactive Streams Publisher to/from various async/reactive types such as CompletableFuture, RxJava Observable, and others. By default, depending on classpath availability, adapters are registered for Reactor, RxJava 1, RxJava 2 types, CompletableFuture, and Java 9+ Flow.Publisher.
适配器注册表,用于使Reactive Streams Publisher适应各种异步/反应类型,例如CompletableFuture,RxJava Observable等。 默认情况下,根据类路径的可用性,为Reactor,RxJava 1,RxJava 2类型,CompletableFuture和Java 9+ Flow.Publisher注册适配器。
果然,它可以处理多种 Reactive Stream 的发布器,它提到了 Reactor 、RxJava 、jdk9版本的 Flow
等。
6.9 一组ResultHandler
复制 @ Bean // 处理HttpEntity和ResponseEntity
public ResponseEntityResultHandler responseEntityResultHandler() {
return new ResponseEntityResultHandler(serverCodecConfigurer() . getWriters() ,
webFluxContentTypeResolver() , webFluxAdapterRegistry()) ;
}
@ Bean // 处理@ResponseBody类型的
public ResponseBodyResultHandler responseBodyResultHandler() {
return new ResponseBodyResultHandler(serverCodecConfigurer() . getWriters() ,
webFluxContentTypeResolver() , webFluxAdapterRegistry()) ;
}
@ 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 // 处理返回值类型为ServerResponse
public ServerResponseResultHandler serverResponseResultHandler() {
List < ViewResolver > resolvers = getViewResolverRegistry() . getViewResolvers ();
ServerResponseResultHandler handler = new ServerResponseResultHandler() ;
handler . setMessageWriters ( serverCodecConfigurer() . getWriters ());
handler . setViewResolvers (resolvers);
return handler;
}
WebFlux 提供了4种 ResultHandler
,每种功能已标注在源码中。
7. ResourceChainCustomizerConfiguration
在最底下还有一个,不过它的配置很简单:
复制 @ Configuration
@ ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
@ Bean
public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer () {
return new ResourceChainResourceHandlerRegistrationCustomizer() ;
}
}
发现它有一个 @ConditionalOnEnableResourceChain
注解,它的作用咱不深追究了,它实际是跟一个 application.properties
中的配置有关:spring.resources.chain.strategy.fixed.enabled
,如果它配置为true,这个条件才生效,默认不生效,不再深究。
8. 小结
WebFluxAutoConfiguration
的配置整体与 WebMvcAutoConfiguration
非常相似,其中不乏包括几个核心组件。
WebFluxAutoConfiguration
默认配置的Web容器是Netty而非 Tomcat 等传统 Servlet 容器。
大部分比较熟悉的组件都在 DelegatingWebFluxConfiguration
的父类 WebFluxConfigurationSupport
中注册。