Merge pull request #39467 from BenchmarkingBuffalo

* pr/39467:
  Add customizer callback for WebHttpHandlerBuilder

Closes gh-39467
This commit is contained in:
Scott Frederick 2024-02-08 14:50:10 -06:00
commit 676b6334d3
4 changed files with 80 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 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.
@ -41,6 +41,7 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
*
* @author Brian Clozel
* @author Stephane Nicoll
* @author Lasse Wulff
* @since 2.0.0
*/
@AutoConfiguration(after = { WebFluxAutoConfiguration.class })
@ -60,8 +61,11 @@ public class HttpHandlerAutoConfiguration {
}
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider,
ObjectProvider<WebHttpHandlerBuilderCustomizer> handlerBuilderCustomizers) {
WebHttpHandlerBuilder handlerBuilder = WebHttpHandlerBuilder.applicationContext(this.applicationContext);
handlerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(handlerBuilder));
HttpHandler httpHandler = handlerBuilder.build();
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);

View File

@ -0,0 +1,36 @@
/*
* Copyright 2012-2024 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
*
* https://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.server.adapter.WebHttpHandlerBuilder;
/**
* Callback interface used to customize a {@link WebHttpHandlerBuilder}.
*
* @author Lasse Wulff
* @since 3.3.0
*/
@FunctionalInterface
public interface WebHttpHandlerBuilderCustomizer {
/**
* Callback to customize a {@link WebHttpHandlerBuilder} instance.
* @param webHttpHandlerBuilder the handlerBuilder to customize
*/
void customize(WebHttpHandlerBuilder webHttpHandlerBuilder);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -23,8 +23,13 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
@ -40,6 +45,7 @@ import static org.springframework.web.reactive.function.server.RouterFunctions.r
* @author Brian Clozel
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Lasse Wulff
*/
class HttpHandlerAutoConfigurationTests {
@ -66,6 +72,20 @@ class HttpHandlerAutoConfigurationTests {
.run((context) -> assertThat(context).hasSingleBean(HttpHandler.class));
}
@Test
void customizersAreCalled() {
this.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
.withUserConfiguration(WebHttpHandlerBuilderCustomizers.class)
.run((context) -> {
assertThat(context).hasSingleBean(HttpHandler.class);
HttpHandler httpHandler = context.getBean(HttpHandler.class);
ServerHttpRequest request = MockServerHttpRequest.get("").build();
ServerHttpResponse response = new MockServerHttpResponse();
httpHandler.handle(request, response).block();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.I_AM_A_TEAPOT);
});
}
@Test
void shouldConfigureBasePathCompositeHandler() {
this.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
@ -104,4 +124,18 @@ class HttpHandlerAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class WebHttpHandlerBuilderCustomizers {
@Bean
WebHttpHandlerBuilderCustomizer customizerDecorator() {
return (webHttpHandlerBuilder) -> webHttpHandlerBuilder
.httpHandlerDecorator(((httpHandler) -> (request, response) -> {
response.setStatusCode(HttpStatus.I_AM_A_TEAPOT);
return response.setComplete();
}));
}
}
}

View File

@ -44,6 +44,8 @@ The auto-configuration adds the following features on top of Spring's defaults:
If you want to keep Spring Boot WebFlux features and you want to add additional {spring-framework-docs}/web/webflux/config.html[WebFlux configuration], you can add your own `@Configuration` class of type `WebFluxConfigurer` but *without* `@EnableWebFlux`.
If you want to add additional customization to the auto-configured `HttpHandler`, you can define beans of type `WebHttpHandlerBuilderCustomizer` and use them to modify the `WebHttpHandlerBuilder`.
If you want to take complete control of Spring WebFlux, you can add your own `@Configuration` annotated with `@EnableWebFlux`.