Skip to content

Commit 676b633

Browse files
Merge pull request #39467 from BenchmarkingBuffalo
* pr/39467: Add customizer callback for WebHttpHandlerBuilder Closes gh-39467
2 parents a40ae61 + 0a11cdc commit 676b633

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfiguration.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
4141
*
4242
* @author Brian Clozel
4343
* @author Stephane Nicoll
44+
* @author Lasse Wulff
4445
* @since 2.0.0
4546
*/
4647
@AutoConfiguration(after = { WebFluxAutoConfiguration.class })
@@ -60,8 +61,11 @@ public AnnotationConfig(ApplicationContext applicationContext) {
6061
}
6162

6263
@Bean
63-
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
64-
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
64+
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider,
65+
ObjectProvider<WebHttpHandlerBuilderCustomizer> handlerBuilderCustomizers) {
66+
WebHttpHandlerBuilder handlerBuilder = WebHttpHandlerBuilder.applicationContext(this.applicationContext);
67+
handlerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(handlerBuilder));
68+
HttpHandler httpHandler = handlerBuilder.build();
6569
WebFluxProperties properties = propsProvider.getIfAvailable();
6670
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
6771
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.web.reactive;
18+
19+
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
20+
21+
/**
22+
* Callback interface used to customize a {@link WebHttpHandlerBuilder}.
23+
*
24+
* @author Lasse Wulff
25+
* @since 3.3.0
26+
*/
27+
@FunctionalInterface
28+
public interface WebHttpHandlerBuilderCustomizer {
29+
30+
/**
31+
* Callback to customize a {@link WebHttpHandlerBuilder} instance.
32+
* @param webHttpHandlerBuilder the handlerBuilder to customize
33+
*/
34+
void customize(WebHttpHandlerBuilder webHttpHandlerBuilder);
35+
36+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,8 +23,13 @@
2323
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
2424
import org.springframework.context.annotation.Bean;
2525
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.http.HttpStatus;
2627
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
2728
import org.springframework.http.server.reactive.HttpHandler;
29+
import org.springframework.http.server.reactive.ServerHttpRequest;
30+
import org.springframework.http.server.reactive.ServerHttpResponse;
31+
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
32+
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
2833
import org.springframework.web.reactive.DispatcherHandler;
2934
import org.springframework.web.reactive.function.server.RouterFunction;
3035
import org.springframework.web.reactive.function.server.ServerResponse;
@@ -40,6 +45,7 @@
4045
* @author Brian Clozel
4146
* @author Stephane Nicoll
4247
* @author Andy Wilkinson
48+
* @author Lasse Wulff
4349
*/
4450
class HttpHandlerAutoConfigurationTests {
4551

@@ -66,6 +72,20 @@ void shouldConfigureHttpHandlerWithoutWebFluxAutoConfiguration() {
6672
.run((context) -> assertThat(context).hasSingleBean(HttpHandler.class));
6773
}
6874

75+
@Test
76+
void customizersAreCalled() {
77+
this.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
78+
.withUserConfiguration(WebHttpHandlerBuilderCustomizers.class)
79+
.run((context) -> {
80+
assertThat(context).hasSingleBean(HttpHandler.class);
81+
HttpHandler httpHandler = context.getBean(HttpHandler.class);
82+
ServerHttpRequest request = MockServerHttpRequest.get("").build();
83+
ServerHttpResponse response = new MockServerHttpResponse();
84+
httpHandler.handle(request, response).block();
85+
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.I_AM_A_TEAPOT);
86+
});
87+
}
88+
6989
@Test
7090
void shouldConfigureBasePathCompositeHandler() {
7191
this.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
@@ -104,4 +124,18 @@ WebHandler webHandler() {
104124

105125
}
106126

127+
@Configuration(proxyBeanMethods = false)
128+
static class WebHttpHandlerBuilderCustomizers {
129+
130+
@Bean
131+
WebHttpHandlerBuilderCustomizer customizerDecorator() {
132+
return (webHttpHandlerBuilder) -> webHttpHandlerBuilder
133+
.httpHandlerDecorator(((httpHandler) -> (request, response) -> {
134+
response.setStatusCode(HttpStatus.I_AM_A_TEAPOT);
135+
return response.setComplete();
136+
}));
137+
}
138+
139+
}
140+
107141
}

spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/reactive.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ The auto-configuration adds the following features on top of Spring's defaults:
4444

4545
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`.
4646

47+
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`.
48+
4749
If you want to take complete control of Spring WebFlux, you can add your own `@Configuration` annotated with `@EnableWebFlux`.
4850

4951

0 commit comments

Comments
 (0)