Add WebFluxRegistrations for custom WebFlux beans

This commit adds a new `WebFluxRegistrations` interface that
allows developers to register custom instances of key WebFlux
infrastructure components, such as `RequestMappingHandlerMapping`
and `RequestMappingHandlerAdapter`.

Closes gh-13997
This commit is contained in:
artsiom 2018-08-17 16:59:14 +02:00 committed by Brian Clozel
parent ba2f2a3727
commit 1c224e5fbb
3 changed files with 157 additions and 1 deletions

View File

@ -71,6 +71,8 @@ import org.springframework.web.reactive.resource.ResourceResolver;
import org.springframework.web.reactive.resource.VersionResourceResolver;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.reactive.result.view.ViewResolver;
/**
@ -226,8 +228,12 @@ public class WebFluxAutoConfiguration {
private final WebFluxProperties webFluxProperties;
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties) {
private final WebFluxRegistrations webFluxRegistrations;
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
this.webFluxProperties = webFluxProperties;
this.webFluxRegistrations = webFluxRegistrations.getIfUnique();
}
@Bean
@ -249,6 +255,24 @@ public class WebFluxAutoConfiguration {
return ValidatorAdapter.get(getApplicationContext(), getValidator());
}
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.webFluxRegistrations != null && this.webFluxRegistrations
.getRequestMappingHandlerAdapter() != null) {
return this.webFluxRegistrations.getRequestMappingHandlerAdapter();
}
return super.createRequestMappingHandlerAdapter();
}
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if (this.webFluxRegistrations != null && this.webFluxRegistrations
.getRequestMappingHandlerMapping() != null) {
return this.webFluxRegistrations.getRequestMappingHandlerMapping();
}
return super.createRequestMappingHandlerMapping();
}
}
@Configuration

View File

@ -0,0 +1,53 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.reactive;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
/**
* Interface to register key components of the {@link WebFluxAutoConfiguration} in place
* of the default ones provided by Spring WebFlux.
* <p>
* All custom instances are later processed by Boot and Spring WebFlux configurations. A
* single instance of this component should be registered, otherwise making it impossible
* to choose from redundant WebFlux components.
*
* @author Artsiom Yudovin
* @since 2.1.0
* @see org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration.EnableWebFluxConfiguration
*/
public interface WebFluxRegistrations {
/**
* Return the custom {@link RequestMappingHandlerMapping} that should be used and
* processed by the WebFlux configuration.
* @return the custom {@link RequestMappingHandlerMapping} instance
*/
default RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return null;
}
/**
* Return the custom {@link RequestMappingHandlerAdapter} that should be used and
* processed by the WebFlux configuration.
* @return the custom {@link RequestMappingHandlerAdapter} instance
*/
default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return null;
}
}

View File

@ -33,6 +33,7 @@ import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
@ -370,6 +371,33 @@ public class WebFluxAutoConfigurationTests {
});
}
@Test
public void customRequestMappingHandlerMapping() {
this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerMapping.class)
.run((context) -> assertThat(context)
.getBean(RequestMappingHandlerMapping.class)
.isInstanceOf(MyRequestMappingHandlerMapping.class));
}
@Test
public void customRequestMappingHandlerAdapter() {
this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerAdapter.class)
.run((context) -> assertThat(context)
.getBean(RequestMappingHandlerAdapter.class)
.isInstanceOf(MyRequestMappingHandlerAdapter.class));
}
@Test
public void multipleWebFluxRegistrations() {
this.contextRunner.withUserConfiguration(MultipleWebFluxRegistrations.class)
.run((context) -> {
assertThat(context.getBean(RequestMappingHandlerMapping.class))
.isNotInstanceOf(MyRequestMappingHandlerMapping.class);
assertThat(context.getBean(RequestMappingHandlerAdapter.class))
.isNotInstanceOf(MyRequestMappingHandlerAdapter.class);
});
}
@Configuration
protected static class CustomArgumentResolvers {
@ -485,4 +513,55 @@ public class WebFluxAutoConfigurationTests {
}
@Configuration
static class CustomRequestMappingHandlerAdapter {
@Bean
public WebFluxRegistrations webMvcRegistrationsHandlerAdapter() {
return new WebFluxRegistrations() {
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return new WebFluxAutoConfigurationTests.MyRequestMappingHandlerAdapter();
}
};
}
}
private static class MyRequestMappingHandlerAdapter
extends RequestMappingHandlerAdapter {
}
@Configuration
@Import({ WebFluxAutoConfigurationTests.CustomRequestMappingHandlerMapping.class,
WebFluxAutoConfigurationTests.CustomRequestMappingHandlerAdapter.class })
static class MultipleWebFluxRegistrations {
}
@Configuration
static class CustomRequestMappingHandlerMapping {
@Bean
public WebFluxRegistrations webMvcRegistrationsHandlerMapping() {
return new WebFluxRegistrations() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new MyRequestMappingHandlerMapping();
}
};
}
}
private static class MyRequestMappingHandlerMapping
extends RequestMappingHandlerMapping {
}
}