Skip to content

Commit

Permalink
Merge pull request #39467 from BenchmarkingBuffalo
Browse files Browse the repository at this point in the history
* pr/39467:
  Add customizer callback for WebHttpHandlerBuilder

Closes gh-39467
  • Loading branch information
scottfrederick committed Feb 8, 2024
2 parents a40ae61 + 0a11cdc commit 676b633
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -41,6 +41,7 @@
*
* @author Brian Clozel
* @author Stephane Nicoll
* @author Lasse Wulff
* @since 2.0.0
*/
@AutoConfiguration(after = { WebFluxAutoConfiguration.class })
Expand All @@ -60,8 +61,11 @@ public AnnotationConfig(ApplicationContext applicationContext) {
}

@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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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);

}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -23,8 +23,13 @@
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;
Expand All @@ -40,6 +45,7 @@
* @author Brian Clozel
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Lasse Wulff
*/
class HttpHandlerAutoConfigurationTests {

Expand All @@ -66,6 +72,20 @@ void shouldConfigureHttpHandlerWithoutWebFluxAutoConfiguration() {
.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))
Expand Down Expand Up @@ -104,4 +124,18 @@ WebHandler webHandler() {

}

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

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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`.


Expand Down

0 comments on commit 676b633

Please sign in to comment.