Spring Webflux 源碼閱讀之 config包

Spring-webflux --config 源碼閱讀

包名 org.springframework.web.reactive.config

看一張diagram:

config.jpg

介紹

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

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);
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,662評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,282評(píng)論 6 342
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,767評(píng)論 18 399
  • 這其實(shí)應(yīng)該是寫給某位學(xué)生的信。 小盆友: 永遠(yuǎn)不要把“不會(huì)”當(dāng)做一個(gè)理由來拒絕學(xué)習(xí)。今天交給了你一個(gè)任務(wù),很簡單,...
    我在學(xué)校工作這幾年閱讀 937評(píng)論 0 0
  • 這個(gè)說實(shí)話我沒學(xué)出我想要的效果,哭…但我還是要分享下過程滴。嘿嘿嘿 用鉛筆的綠色和黃色起線稿...
    不慌張軒軒w閱讀 819評(píng)論 2 5

友情鏈接更多精彩內(nèi)容