Spring Webflux 源码阅读之 config包

Spring-webflux --config 源码阅读

包名 org.springframework.web.reactive.config

看一张diagram:

config.jpg

介绍

Spring WebFlux配置基础架构。
将此注释添加到@Configuration类中,从WebFluxConfigurationSupport导入Spring Web Reactive配置,例如:


 @Configuration
 @EnableWebFlux
 @ComponentScan(basePackageClasses = MyConfiguration.class)
 public class MyConfiguration {
 }
 

接口 WebFluxConfigurer

定义了回调方法来自定义通过@EnableWebFlux来启用WebFlux应用程序的配置。

@Enablewebflux注释的配置类可以实现这个接口的调用,并提供一个定制默认配置的机会。考虑实现这个接口,并根据需要覆盖相关的方法。

default void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder)

配置如何解决响应请求的内容类型。

default void addCorsMappings(CorsRegistry registry)

配置交叉原点请求处理。

default void configurePathMatching(PathMatchConfigurer configurer)

配置路径匹配选项。 HandlerMappings与路径匹配选项。

default void addResourceHandlers(ResourceHandlerRegistry registry)

为服务静态资源添加资源处理程序。

default void configureArgumentResolvers(ArgumentResolverConfigurer configurer)

配置自定义控制器方法参数的解析器。

default void configureHttpMessageCodecs(ServerCodecConfigurer configurer)

配置自定义HTTP消息读取器和编写器或重写内置的。

default void addFormatters(FormatterRegistry registry)

添加自定义转换器和格式化程序,用于执行控制器方法参数的类型转换和格式化。

@Nullable
default MessageCodesResolver getMessageCodesResolver()

供一个自定义MessageCodesResolver用于数据绑定,而不是DataBinder中默认创建的那个。

default void configureViewResolvers(ViewResolverRegistry registry)

配置视图解析以处理控制器方法的返回值,这些方法依赖于解析视图来呈现响应。默认情况下,所有的控制器方法都依赖于视图解析,除非使用@ responsebody或显式返回ResponseEntity。视图可以显式地指定为字符串返回值或隐式,例如void返回值。

org.springframework.web.reactive.config.CorsRegistration

协助创建映射到路径模式的CorsConfiguration实例。默认情况下,当最大时间设置为30分钟时,允许GET,HEAD和POST请求的所有来源,标题和凭证。

构造方法:

CorsRegistration(java.lang.String pathPattern)
创建一个新的CorsRegistration,允许指定路径的最大时间设置为1800秒(30分钟)的GET,HEAD和POST请求的所有来源,标题和凭证。
CORS配置应该适用的路径;支持精确的路径映射URI(如“/ admin”)以及Ant样式的路径模式(如“/ admin / **”)。

方法:

  • allowCredentials(boolean allowCredentials) 是否支持用户凭据。
  • allowedHeaders(java.lang.String... headers) 设置飞行前请求可以在实际请求中使用的标题列表。如果它是一个:cache - control、content - language、Expires、last - modified或Pragma,根据CORS规范,则不需要列出header名称。
    默认情况下,所有标题都是允许的。
  • allowedMethods(java.lang.String... methods) 设置允许的HTTP方法
  • allowedOrigins(java.lang.String... origins) 设置允许的来源 特殊值“*”允许所有域,默认情况下所有的来源都是允许的。
  • exposedHeaders(java.lang.String... headers) 设置“简单”标题以外的响应标题列表
  • getCorsConfiguration()
  • getPathPattern()
  • maxAge(long maxAge) 配置客户端可以缓存飞行前请求响应的时间,以秒为单位。

org.springframework.web.reactive.config.CorsRegistry

CorsRegistry协助注册CorsConfiguration映射到路径模式。
为指定的路径模式启用跨域请求处理

方法:

  • addMapping(java.lang.String pathPattern) 为指定的路径模式启用跨域请求处理。支持精确的路径映射URI(如“/ admin”)以及Ant样式的路径模式(如“/ admin / **”)。默认情况下,允许所有来源,所有标题,凭据和GET,HEAD和POST方法,并且最大时间设置为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

协助配置HandlerMapping的路径匹配选项。

方法

  • isUseCaseSensitiveMatch()
  • isUseTrailingSlashMatch() 是否与URL匹配,而不管是否存在尾部斜线。如果启用,映射到“/ users”的方法也匹配“/ users /”。 默认值是true。
  • setUseCaseSensitiveMatch(java.lang.Boolean caseSensitiveMatch) 是否与网址匹配,而不考虑其情况。
  • setUseTrailingSlashMatch(java.lang.Boolean trailingSlashMatch) 是否与URL匹配,而不管是否以斜杠结尾。

    @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

协助完成资源和转换器的注册

构造器

  • ResourceChainRegistration(boolean cacheResources)
  • ResourceChainRegistration(boolean cacheResources)

方法

  • addResolver(ResourceResolver resolver) 将一个资源解析器添加到链中。
  • addTransformer(ResourceTransformer transformer) 向链中添加资源转换器器。
  • 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存储资源处理程序的注册,以提供静态资源(如图像,css文件和其他),包括设置优化的高速缓存头,以便在Web浏览器中进行高效加载。资源可以从Web应用程序根目录下的位置,类路径和其他位置提供。

要创建资源处理程序,请使用addResourceHandler(String ...)提供应为其调用处理程序以提供静态资源(例如“/ resources / **”)的URL路径模式。

然后在返回的ResourceHandlerRegistration上使用其他方法来添加一个或多个从(例如{“/”,“classpath:/ META-INF / public-web-resources /”})静态内容的位置,或者指定一个缓存期间服务的资源。

构造器

  • ResourceHandlerRegistry(ResourceLoader resourceLoader) 为给定资源加载器(通常是应用程序上下文)创建新的资源处理程序注册表。

方法

  • addResourceHandler(java.lang.String... patterns) 添加一个资源处理程序,用于根据指定的URL路径模式提供静态资源。 处理程序将针对每个与指定路径模式匹配的传入请求进行调用。像“/static/ **”或“/css/{filename:\w+\.css}”的模式是允许的。有关语法的更多详细信息,请参阅PathPattern。
  • getHandlerMapping() 返回映射资源处理程序的处理程序映射;或者在没有注册的情况下为空。
  • hasMappingForPattern(java.lang.String pathPattern) 资源处理程序是否已经注册了给定的路径模式。
  • setOrder(int order) 指定相对于Spring配置中配置的其他HandlerMappings进行资源处理的顺序。 使用的默认值是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

协助创建和配置静态资源处理程序。

构造器

  • ResourceHandlerRegistration(ResourceLoader resourceLoader, java.lang.String... pathPatterns)
    创建一个ResourceHandlerRegistration实例。

    • resourceLoader :用于将字符串位置转换为资源的资源加载器
    • pathPatterns - 一个或多个资源URL路径模式

方法

  • addResourceLocations(java.lang.String... resourceLocations)
    • 添加一个或多个资源位置来服务静态内容。每个位置必须指向一个有效的目录。多个位置可以指定为逗号分隔的列表,并且位置将按照指定的顺序对给定的资源进行检查。
    • 例如,{“/”,“classpath:/ META-INF / public-web-resources /”}允许资源从Web应用程序的根目录和任何包含/ META-INF / public-web-resources /的目录,Web应用程序根目录中的资源优先。
  • getPathPatterns()
  • getRequestHandler()
  • resourceChain(boolean cacheResources)
  • resourceChain(boolean cacheResources, Cache cache)
  • setCacheControl(CacheControl cacheControl) 指定应该由资源处理程序使用的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

协助配置UrlBasedViewResolver的属性。

构造器

  • UrlBasedViewResolverRegistration(UrlBasedViewResolver viewResolver)

方法

  • getViewResolver()
  • prefix(java.lang.String prefix) 设置在构建URL时附加到视图名称的前缀。
  • suffix(java.lang.String suffix) 设置在构建URL时附加到视图名称的后缀。
  • viewClass(java.lang.Class<?> viewClass) 设置应该用于创建视图的视图类。
  • viewNames(java.lang.String... viewNames) 设置可由该视图解析器处理的视图名称(或名称模式)。视图名称可以包含简单的通配符,这样'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

协助配置一个ViewResolver的链,支持不同的模板机制。另外,还可以根据所请求的内容类型配置defaultView以进行渲染,例如, JSON,XML等

构造器

  • ViewResolverRegistry(ApplicationContext applicationContext)

方法

  • defaultViews(View... defaultViews) 设置与任何视图名称关联的默认视图,并根据请求的内容类型的最佳匹配进行选择。使用HttpMessageWriterView来调整和使用任何现有的HttpMessageWriter(例如JSON,XML)作为一个视图。
  • freeMarker() 注册一个带有“.ftl”后缀的FreeMarkerViewResolver。
  • getDefaultViews()
  • getOrder()
  • getViewResolvers()
  • hasRegistrations() 是否有任何视图解析器已被注册。
  • order(int order) 设置ViewResolutionResultHandler的顺序。 默认情况下,此属性未设置,这意味着结果处理程序将按顺序排列。
  • viewResolver(ViewResolver viewResolver) 注册一个ViewResolver bean实例。这可能有助于配置第三方解析器实现,或者在这个类中不公开一些需要设置的高级属性时,可以替代其他注册方法。

    @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

所有实现的接口

Aware, ApplicationContextAware

Spring WebFlux配置的主要类。直接导入或扩展和重写受保护的方法来自定义。



@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

所有实现的接口

WebFluxConfigurer

将WebFluxConfigurer委托给一个或多个。



    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的一个子类,用于检测并委托所有类型为WebFluxConfigurer的bean,允许它们自定义由WebFluxConfigurationSupport提供的配置。这是由@EnableWebFlux实际导入的类。


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,358评论 6 343
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • 这其实应该是写给某位学生的信。 小盆友: 永远不要把“不会”当做一个理由来拒绝学习。今天交给了你一个任务,很简单,...
    我在学校工作这几年阅读 753评论 0 0
  • 这个说实话我没学出我想要的效果,哭…但我还是要分享下过程滴。嘿嘿嘿 用铅笔的绿色和黄色起线稿...
    不慌張轩轩w阅读 747评论 2 5