Spring-webflux --config 源碼閱讀
包名 org.springframework.web.reactive.config
看一張diagram:

介紹
Spring WebFlux配置基礎(chǔ)架構(gòu)。
將此注釋添加到@Configuration類中,從WebFluxConfigurationSupport導(dǎo)入Spring Web Reactive配置,例如:
@Configuration
@EnableWebFlux
@ComponentScan(basePackageClasses = MyConfiguration.class)
public class MyConfiguration {
}
接口 WebFluxConfigurer
定義了回調(diào)方法來自定義通過@EnableWebFlux來啟用WebFlux應(yīng)用程序的配置。
@Enablewebflux注釋的配置類可以實(shí)現(xiàn)這個(gè)接口的調(diào)用,并提供一個(gè)定制默認(rèn)配置的機(jī)會(huì)??紤]實(shí)現(xiàn)這個(gè)接口,并根據(jù)需要覆蓋相關(guān)的方法。
default void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder)
配置如何解決響應(yīng)請(qǐng)求的內(nèi)容類型。
default void addCorsMappings(CorsRegistry registry)
配置交叉原點(diǎn)請(qǐng)求處理。
default void configurePathMatching(PathMatchConfigurer configurer)
配置路徑匹配選項(xiàng)。 HandlerMappings與路徑匹配選項(xiàng)。
default void addResourceHandlers(ResourceHandlerRegistry registry)
為服務(wù)靜態(tài)資源添加資源處理程序。
default void configureArgumentResolvers(ArgumentResolverConfigurer configurer)
配置自定義控制器方法參數(shù)的解析器。
default void configureHttpMessageCodecs(ServerCodecConfigurer configurer)
配置自定義HTTP消息讀取器和編寫器或重寫內(nèi)置的。
default void addFormatters(FormatterRegistry registry)
添加自定義轉(zhuǎn)換器和格式化程序,用于執(zhí)行控制器方法參數(shù)的類型轉(zhuǎn)換和格式化。
@Nullable
default MessageCodesResolver getMessageCodesResolver()
供一個(gè)自定義MessageCodesResolver用于數(shù)據(jù)綁定,而不是DataBinder中默認(rèn)創(chuàng)建的那個(gè)。
default void configureViewResolvers(ViewResolverRegistry registry)
配置視圖解析以處理控制器方法的返回值,這些方法依賴于解析視圖來呈現(xiàn)響應(yīng)。默認(rèn)情況下,所有的控制器方法都依賴于視圖解析,除非使用@ responsebody或顯式返回ResponseEntity。視圖可以顯式地指定為字符串返回值或隱式,例如void返回值。
類
org.springframework.web.reactive.config.CorsRegistration
協(xié)助創(chuàng)建映射到路徑模式的CorsConfiguration實(shí)例。默認(rèn)情況下,當(dāng)最大時(shí)間設(shè)置為30分鐘時(shí),允許GET,HEAD和POST請(qǐng)求的所有來源,標(biāo)題和憑證。
構(gòu)造方法:
CorsRegistration(java.lang.String pathPattern)
創(chuàng)建一個(gè)新的CorsRegistration,允許指定路徑的最大時(shí)間設(shè)置為1800秒(30分鐘)的GET,HEAD和POST請(qǐng)求的所有來源,標(biāo)題和憑證。
CORS配置應(yīng)該適用的路徑;支持精確的路徑映射URI(如“/ admin”)以及Ant樣式的路徑模式(如“/ admin / **”)。
方法:
- allowCredentials(boolean allowCredentials) 是否支持用戶憑據(jù)。
- allowedHeaders(java.lang.String... headers) 設(shè)置飛行前請(qǐng)求可以在實(shí)際請(qǐng)求中使用的標(biāo)題列表。如果它是一個(gè):cache - control、content - language、Expires、last - modified或Pragma,根據(jù)CORS規(guī)范,則不需要列出header名稱。
默認(rèn)情況下,所有標(biāo)題都是允許的。 - allowedMethods(java.lang.String... methods) 設(shè)置允許的HTTP方法
- allowedOrigins(java.lang.String... origins) 設(shè)置允許的來源 特殊值“*”允許所有域,默認(rèn)情況下所有的來源都是允許的。
- exposedHeaders(java.lang.String... headers) 設(shè)置“簡單”標(biāo)題以外的響應(yīng)標(biāo)題列表
- getCorsConfiguration()
- getPathPattern()
- maxAge(long maxAge) 配置客戶端可以緩存飛行前請(qǐng)求響應(yīng)的時(shí)間,以秒為單位。
org.springframework.web.reactive.config.CorsRegistry
CorsRegistry協(xié)助注冊(cè)CorsConfiguration映射到路徑模式。
為指定的路徑模式啟用跨域請(qǐng)求處理
方法:
- addMapping(java.lang.String pathPattern) 為指定的路徑模式啟用跨域請(qǐng)求處理。支持精確的路徑映射URI(如“/ admin”)以及Ant樣式的路徑模式(如“/ admin / **”)。默認(rèn)情況下,允許所有來源,所有標(biāo)題,憑據(jù)和GET,HEAD和POST方法,并且最大時(shí)間設(shè)置為30分鐘。
- protected java.util.Map<java.lang.String,CorsConfiguration> getCorsConfigurations()
private final List<CorsRegistration> registrations = new ArrayList<>();
public CorsRegistration addMapping(String pathPattern) {
CorsRegistration registration = new CorsRegistration(pathPattern);
this.registrations.add(registration);
return registration;
}
protected Map<String, CorsConfiguration> getCorsConfigurations() {
Map<String, CorsConfiguration> configs = new LinkedHashMap<>(this.registrations.size());
for (CorsRegistration registration : this.registrations) {
configs.put(registration.getPathPattern(), registration.getCorsConfiguration());
}
return configs;
}
org.springframework.web.reactive.config.PathMatchConfigurer
協(xié)助配置HandlerMapping的路徑匹配選項(xiàng)。
方法
- isUseCaseSensitiveMatch()
- isUseTrailingSlashMatch() 是否與URL匹配,而不管是否存在尾部斜線。如果啟用,映射到“/ users”的方法也匹配“/ users /”。 默認(rèn)值是true。
- setUseCaseSensitiveMatch(java.lang.Boolean caseSensitiveMatch) 是否與網(wǎng)址匹配,而不考慮其情況。
- setUseTrailingSlashMatch(java.lang.Boolean trailingSlashMatch) 是否與URL匹配,而不管是否以斜杠結(jié)尾。
@Nullable
private Boolean trailingSlashMatch;
@Nullable
private Boolean caseSensitiveMatch;
public PathMatchConfigurer setUseCaseSensitiveMatch(Boolean caseSensitiveMatch) {
this.caseSensitiveMatch = caseSensitiveMatch;
return this;
}
public PathMatchConfigurer setUseTrailingSlashMatch(Boolean trailingSlashMatch) {
this.trailingSlashMatch = trailingSlashMatch;
return this;
}
@Nullable
protected Boolean isUseTrailingSlashMatch() {
return this.trailingSlashMatch;
}
@Nullable
protected Boolean isUseCaseSensitiveMatch() {
return this.caseSensitiveMatch;
}
org.springframework.web.reactive.config.ResourceChainRegistration
協(xié)助完成資源和轉(zhuǎn)換器的注冊(cè)
構(gòu)造器
- ResourceChainRegistration(boolean cacheResources)
- ResourceChainRegistration(boolean cacheResources)
方法
- addResolver(ResourceResolver resolver) 將一個(gè)資源解析器添加到鏈中。
- addTransformer(ResourceTransformer transformer) 向鏈中添加資源轉(zhuǎn)換器器。
- getResourceResolvers()
- getResourceTransformers()
private static final String DEFAULT_CACHE_NAME = "spring-resource-chain-cache";
private static final boolean isWebJarsAssetLocatorPresent = ClassUtils.isPresent(
"org.webjars.WebJarAssetLocator", ResourceChainRegistration.class.getClassLoader());
private final List<ResourceResolver> resolvers = new ArrayList<>(4);
private final List<ResourceTransformer> transformers = new ArrayList<>(4);
private boolean hasVersionResolver;
private boolean hasPathResolver;
private boolean hasCssLinkTransformer;
private boolean hasWebjarsResolver;
public ResourceChainRegistration(boolean cacheResources) {
this(cacheResources, cacheResources ? new ConcurrentMapCache(DEFAULT_CACHE_NAME) : null);
}
public ResourceChainRegistration(boolean cacheResources, @Nullable Cache cache) {
Assert.isTrue(!cacheResources || cache != null, "'cache' is required when cacheResources=true");
if (cacheResources) {
this.resolvers.add(new CachingResourceResolver(cache));
this.transformers.add(new CachingResourceTransformer(cache));
}
}
public ResourceChainRegistration addResolver(ResourceResolver resolver) {
Assert.notNull(resolver, "The provided ResourceResolver should not be null");
this.resolvers.add(resolver);
if (resolver instanceof VersionResourceResolver) {
this.hasVersionResolver = true;
}
else if (resolver instanceof PathResourceResolver) {
this.hasPathResolver = true;
}
else if (resolver instanceof WebJarsResourceResolver) {
this.hasWebjarsResolver = true;
}
return this;
}
public ResourceChainRegistration addTransformer(ResourceTransformer transformer) {
Assert.notNull(transformer, "The provided ResourceTransformer should not be null");
this.transformers.add(transformer);
if (transformer instanceof CssLinkResourceTransformer) {
this.hasCssLinkTransformer = true;
}
return this;
}
protected List<ResourceResolver> getResourceResolvers() {
if (!this.hasPathResolver) {
List<ResourceResolver> result = new ArrayList<>(this.resolvers);
if (isWebJarsAssetLocatorPresent && !this.hasWebjarsResolver) {
result.add(new WebJarsResourceResolver());
}
result.add(new PathResourceResolver());
return result;
}
return this.resolvers;
}
protected List<ResourceTransformer> getResourceTransformers() {
if (this.hasVersionResolver && !this.hasCssLinkTransformer) {
List<ResourceTransformer> result = new ArrayList<>(this.transformers);
boolean hasTransformers = !this.transformers.isEmpty();
boolean hasCaching = hasTransformers && this.transformers.get(0) instanceof CachingResourceTransformer;
result.add(hasCaching ? 1 : 0, new CssLinkResourceTransformer());
return result;
}
return this.transformers;
}
org.springframework.web.reactive.config.ResourceHandlerRegistry
通過Spring WebFlux存儲(chǔ)資源處理程序的注冊(cè),以提供靜態(tài)資源(如圖像,css文件和其他),包括設(shè)置優(yōu)化的高速緩存頭,以便在Web瀏覽器中進(jìn)行高效加載。資源可以從Web應(yīng)用程序根目錄下的位置,類路徑和其他位置提供。
要?jiǎng)?chuàng)建資源處理程序,請(qǐng)使用addResourceHandler(String ...)提供應(yīng)為其調(diào)用處理程序以提供靜態(tài)資源(例如“/ resources / **”)的URL路徑模式。
然后在返回的ResourceHandlerRegistration上使用其他方法來添加一個(gè)或多個(gè)從(例如{“/”,“classpath:/ META-INF / public-web-resources /”})靜態(tài)內(nèi)容的位置,或者指定一個(gè)緩存期間服務(wù)的資源。
構(gòu)造器
- ResourceHandlerRegistry(ResourceLoader resourceLoader) 為給定資源加載器(通常是應(yīng)用程序上下文)創(chuàng)建新的資源處理程序注冊(cè)表。
方法
- addResourceHandler(java.lang.String... patterns) 添加一個(gè)資源處理程序,用于根據(jù)指定的URL路徑模式提供靜態(tài)資源。 處理程序?qū)⑨槍?duì)每個(gè)與指定路徑模式匹配的傳入請(qǐng)求進(jìn)行調(diào)用。像“/static/ **”或“/css/{filename:\w+\.css}”的模式是允許的。有關(guān)語法的更多詳細(xì)信息,請(qǐng)參閱PathPattern。
- getHandlerMapping() 返回映射資源處理程序的處理程序映射;或者在沒有注冊(cè)的情況下為空。
- hasMappingForPattern(java.lang.String pathPattern) 資源處理程序是否已經(jīng)注冊(cè)了給定的路徑模式。
- setOrder(int order) 指定相對(duì)于Spring配置中配置的其他HandlerMappings進(jìn)行資源處理的順序。 使用的默認(rèn)值是Integer.MAX_VALUE-1。
private final ResourceLoader resourceLoader;
private final List<ResourceHandlerRegistration> registrations = new ArrayList<>();
private int order = Integer.MAX_VALUE -1;
public ResourceHandlerRegistry(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public ResourceHandlerRegistration addResourceHandler(String... patterns) {
ResourceHandlerRegistration registration = new ResourceHandlerRegistration(this.resourceLoader, patterns);
this.registrations.add(registration);
return registration;
}
public boolean hasMappingForPattern(String pathPattern) {
for (ResourceHandlerRegistration registration : this.registrations) {
if (Arrays.asList(registration.getPathPatterns()).contains(pathPattern)) {
return true;
}
}
return false;
}
public ResourceHandlerRegistry setOrder(int order) {
this.order = order;
return this;
}
@Nullable
protected AbstractUrlHandlerMapping getHandlerMapping() {
if (this.registrations.isEmpty()) {
return null;
}
Map<String, WebHandler> urlMap = new LinkedHashMap<>();
for (ResourceHandlerRegistration registration : this.registrations) {
for (String pathPattern : registration.getPathPatterns()) {
ResourceWebHandler handler = registration.getRequestHandler();
try {
handler.afterPropertiesSet();
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex);
}
urlMap.put(pathPattern, handler);
}
}
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(this.order);
handlerMapping.setUrlMap(urlMap);
return handlerMapping;
}
org.springframework.web.reactive.config.ResourceHandlerRegistration
協(xié)助創(chuàng)建和配置靜態(tài)資源處理程序。
構(gòu)造器
-
ResourceHandlerRegistration(ResourceLoader resourceLoader, java.lang.String... pathPatterns)
創(chuàng)建一個(gè)ResourceHandlerRegistration實(shí)例。- resourceLoader :用于將字符串位置轉(zhuǎn)換為資源的資源加載器
- pathPatterns - 一個(gè)或多個(gè)資源URL路徑模式
方法
- addResourceLocations(java.lang.String... resourceLocations)
- 添加一個(gè)或多個(gè)資源位置來服務(wù)靜態(tài)內(nèi)容。每個(gè)位置必須指向一個(gè)有效的目錄。多個(gè)位置可以指定為逗號(hào)分隔的列表,并且位置將按照指定的順序?qū)o定的資源進(jìn)行檢查。
- 例如,{“/”,“classpath:/ META-INF / public-web-resources /”}允許資源從Web應(yīng)用程序的根目錄和任何包含/ META-INF / public-web-resources /的目錄,Web應(yīng)用程序根目錄中的資源優(yōu)先。
- getPathPatterns()
- getRequestHandler()
- resourceChain(boolean cacheResources)
- resourceChain(boolean cacheResources, Cache cache)
- setCacheControl(CacheControl cacheControl) 指定應(yīng)該由資源處理程序使用的CacheControl。
private final ResourceLoader resourceLoader;
private final String[] pathPatterns;
private final List<Resource> locations = new ArrayList<>();
@Nullable
private CacheControl cacheControl;
@Nullable
private ResourceChainRegistration resourceChainRegistration;
public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) {
Assert.notNull(resourceLoader, "ResourceLoader is required");
Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling");
this.resourceLoader = resourceLoader;
this.pathPatterns = pathPatterns;
}
public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
for (String location : resourceLocations) {
this.locations.add(this.resourceLoader.getResource(location));
}
return this;
}
public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) {
this.cacheControl = cacheControl;
return this;
}
public ResourceChainRegistration resourceChain(boolean cacheResources) {
this.resourceChainRegistration = new ResourceChainRegistration(cacheResources);
return this.resourceChainRegistration;
}
public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) {
this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache);
return this.resourceChainRegistration;
}
protected String[] getPathPatterns() {
return this.pathPatterns;
}
protected ResourceWebHandler getRequestHandler() {
ResourceWebHandler handler = new ResourceWebHandler();
if (this.resourceChainRegistration != null) {
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
}
handler.setLocations(this.locations);
if (this.cacheControl != null) {
handler.setCacheControl(this.cacheControl);
}
return handler;
}
org.springframework.web.reactive.config.UrlBasedViewResolverRegistration
協(xié)助配置UrlBasedViewResolver的屬性。
構(gòu)造器
- UrlBasedViewResolverRegistration(UrlBasedViewResolver viewResolver)
方法
- getViewResolver()
- prefix(java.lang.String prefix) 設(shè)置在構(gòu)建URL時(shí)附加到視圖名稱的前綴。
- suffix(java.lang.String suffix) 設(shè)置在構(gòu)建URL時(shí)附加到視圖名稱的后綴。
- viewClass(java.lang.Class<?> viewClass) 設(shè)置應(yīng)該用于創(chuàng)建視圖的視圖類。
- viewNames(java.lang.String... viewNames) 設(shè)置可由該視圖解析器處理的視圖名稱(或名稱模式)。視圖名稱可以包含簡單的通配符,這樣'my ',' Report'和'* Repo *'將全部匹配視圖名稱'myReport'。
private final UrlBasedViewResolver viewResolver;
public UrlBasedViewResolverRegistration(UrlBasedViewResolver viewResolver) {
Assert.notNull(viewResolver, "ViewResolver must not be null");
this.viewResolver = viewResolver;
}
public UrlBasedViewResolverRegistration prefix(String prefix) {
this.viewResolver.setPrefix(prefix);
return this;
}
public UrlBasedViewResolverRegistration suffix(String suffix) {
this.viewResolver.setSuffix(suffix);
return this;
}
public UrlBasedViewResolverRegistration viewClass(Class<?> viewClass) {
this.viewResolver.setViewClass(viewClass);
return this;
}
public UrlBasedViewResolverRegistration viewNames(String... viewNames) {
this.viewResolver.setViewNames(viewNames);
return this;
}
protected UrlBasedViewResolver getViewResolver() {
return this.viewResolver;
}
org.springframework.web.reactive.config.ViewResolverRegistry
協(xié)助配置一個(gè)ViewResolver的鏈,支持不同的模板機(jī)制。另外,還可以根據(jù)所請(qǐng)求的內(nèi)容類型配置defaultView以進(jìn)行渲染,例如, JSON,XML等
構(gòu)造器
- ViewResolverRegistry(ApplicationContext applicationContext)
方法
- defaultViews(View... defaultViews) 設(shè)置與任何視圖名稱關(guān)聯(lián)的默認(rèn)視圖,并根據(jù)請(qǐng)求的內(nèi)容類型的最佳匹配進(jìn)行選擇。使用HttpMessageWriterView來調(diào)整和使用任何現(xiàn)有的HttpMessageWriter(例如JSON,XML)作為一個(gè)視圖。
- freeMarker() 注冊(cè)一個(gè)帶有“.ftl”后綴的FreeMarkerViewResolver。
- getDefaultViews()
- getOrder()
- getViewResolvers()
- hasRegistrations() 是否有任何視圖解析器已被注冊(cè)。
- order(int order) 設(shè)置ViewResolutionResultHandler的順序。 默認(rèn)情況下,此屬性未設(shè)置,這意味著結(jié)果處理程序?qū)错樞蚺帕小?/li>
- viewResolver(ViewResolver viewResolver) 注冊(cè)一個(gè)ViewResolver bean實(shí)例。這可能有助于配置第三方解析器實(shí)現(xiàn),或者在這個(gè)類中不公開一些需要設(shè)置的高級(jí)屬性時(shí),可以替代其他注冊(cè)方法。
@Nullable
private final ApplicationContext applicationContext;
private final List<ViewResolver> viewResolvers = new ArrayList<>(4);
private final List<View> defaultViews = new ArrayList<>(4);
@Nullable
private Integer order;
public ViewResolverRegistry(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public UrlBasedViewResolverRegistration freeMarker() {
if (!checkBeanOfType(FreeMarkerConfigurer.class)) {
throw new BeanInitializationException("In addition to a FreeMarker view resolver " +
"there must also be a single FreeMarkerConfig bean in this web application context " +
"(or its parent): FreeMarkerConfigurer is the usual implementation. " +
"This bean may be given any name.");
}
FreeMarkerRegistration registration = new FreeMarkerRegistration();
UrlBasedViewResolver resolver = registration.getViewResolver();
if (this.applicationContext != null) {
resolver.setApplicationContext(this.applicationContext);
}
this.viewResolvers.add(resolver);
return registration;
}
public void viewResolver(ViewResolver viewResolver) {
this.viewResolvers.add(viewResolver);
}
public void defaultViews(View... defaultViews) {
this.defaultViews.addAll(Arrays.asList(defaultViews));
}
public boolean hasRegistrations() {
return (!this.viewResolvers.isEmpty());
}
public void order(int order) {
this.order = order;
}
private boolean checkBeanOfType(Class<?> beanType) {
return (this.applicationContext == null ||
!ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.applicationContext, beanType, false, false)));
}
protected int getOrder() {
return (this.order != null ? this.order : Ordered.LOWEST_PRECEDENCE);
}
protected List<ViewResolver> getViewResolvers() {
return this.viewResolvers;
}
protected List<View> getDefaultViews() {
return this.defaultViews;
}
private static class FreeMarkerRegistration extends UrlBasedViewResolverRegistration {
public FreeMarkerRegistration() {
super(new FreeMarkerViewResolver());
getViewResolver().setSuffix(".ftl");
}
}
org.springframework.web.reactive.config.WebFluxConfigurationSupport
所有實(shí)現(xiàn)的接口
Aware, ApplicationContextAware
Spring WebFlux配置的主要類。直接導(dǎo)入或擴(kuò)展和重寫受保護(hù)的方法來自定義。
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
@Nullable
private ViewResolverRegistry viewResolverRegistry;
@Nullable
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Nullable
public final ApplicationContext getApplicationContext() {
return this.applicationContext;
}
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}
@Bean
@Order(0)
public WebExceptionHandler responseStatusExceptionHandler() {
return new ResponseStatusExceptionHandler();
}
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setContentTypeResolver(webFluxContentTypeResolver());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (useCaseSensitiveMatch != null) {
mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
}
return mapping;
}
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
@Bean
public RequestedContentTypeResolver webFluxContentTypeResolver() {
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder();
configureContentTypeResolver(builder);
return builder.build();
}
protected void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
}
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
protected void addCorsMappings(CorsRegistry registry) {
}
protected final PathMatchConfigurer getPathMatchConfigurer() {
if (this.pathMatchConfigurer == null) {
this.pathMatchConfigurer = new PathMatchConfigurer();
configurePathMatching(this.pathMatchConfigurer);
}
return this.pathMatchConfigurer;
}
public void configurePathMatching(PathMatchConfigurer configurer) {
}
@Bean
public RouterFunctionMapping routerFunctionMapping() {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageReaders(serverCodecConfigurer().getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
@Bean
public HandlerMapping resourceHandlerMapping() {
ResourceLoader resourceLoader = this.applicationContext;
if (resourceLoader == null) {
resourceLoader = new DefaultResourceLoader();
}
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
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;
}
...
org.springframework.web.reactive.config.WebFluxConfigurerComposite
所有實(shí)現(xiàn)的接口
WebFluxConfigurer
將WebFluxConfigurer委托給一個(gè)或多個(gè)。
public class WebFluxConfigurerComposite implements WebFluxConfigurer {
private final List<WebFluxConfigurer> delegates = new ArrayList<>();
public void addWebFluxConfigurers(List<WebFluxConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
this.delegates.forEach(delegate -> delegate.configureContentTypeResolver(builder));
}
@Override
public void addCorsMappings(CorsRegistry registry) {
this.delegates.forEach(delegate -> delegate.addCorsMappings(registry));
}
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
this.delegates.forEach(delegate -> delegate.configurePathMatching(configurer));
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
this.delegates.forEach(delegate -> delegate.addResourceHandlers(registry));
}
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.delegates.forEach(delegate -> delegate.configureArgumentResolvers(configurer));
}
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
this.delegates.forEach(delegate -> delegate.configureHttpMessageCodecs(configurer));
}
@Override
public void addFormatters(FormatterRegistry registry) {
this.delegates.forEach(delegate -> delegate.addFormatters(registry));
}
@Override
public Validator getValidator() {
return createSingleBean(WebFluxConfigurer::getValidator, Validator.class);
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return createSingleBean(WebFluxConfigurer::getMessageCodesResolver, MessageCodesResolver.class);
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
this.delegates.forEach(delegate -> delegate.configureViewResolvers(registry));
}
@Nullable
private <T> T createSingleBean(Function<WebFluxConfigurer, T> factory, Class<T> beanType) {
List<T> result = this.delegates.stream().map(factory).filter(t -> t != null).collect(Collectors.toList());
if (result.isEmpty()) {
return null;
}
else if (result.size() == 1) {
return result.get(0);
}
else {
throw new IllegalStateException("More than one WebFluxConfigurer implements " +
beanType.getSimpleName() + " factory method.");
}
}
}
org.springframework.web.reactive.config.DelegatingWebFluxConfiguration
- java.lang.Object
- org.springframework.web.reactive.config.WebFluxConfigurationSupport
- org.springframework.web.reactive.config.DelegatingWebFluxConfiguration
- org.springframework.web.reactive.config.WebFluxConfigurationSupport
WebFluxConfigurationSupport的一個(gè)子類,用于檢測(cè)并委托所有類型為WebFluxConfigurer的bean,允許它們自定義由WebFluxConfigurationSupport提供的配置。這是由@EnableWebFlux實(shí)際導(dǎo)入的類。
@Configuration
public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport {
private final WebFluxConfigurerComposite configurers = new WebFluxConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebFluxConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebFluxConfigurers(configurers);
}
}
@Override
protected void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
this.configurers.configureContentTypeResolver(builder);
}
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
this.configurers.configurePathMatching(configurer);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
@Override
protected void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.configurers.configureArgumentResolvers(configurer);
}
@Override
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
this.configurers.configureHttpMessageCodecs(configurer);
}
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
@Override
protected Validator getValidator() {
Validator validator = this.configurers.getValidator();
return (validator != null ? validator : super.getValidator());
}
@Override
protected MessageCodesResolver getMessageCodesResolver() {
MessageCodesResolver messageCodesResolver = this.configurers.getMessageCodesResolver();
return (messageCodesResolver != null ? messageCodesResolver : super.getMessageCodesResolver());
}
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
}