Skip to content

Commit 1c224e5

Browse files
artsiombclozel
authored andcommitted
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
1 parent ba2f2a3 commit 1c224e5

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
import org.springframework.web.reactive.resource.VersionResourceResolver;
7272
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
7373
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
74+
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
75+
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
7476
import org.springframework.web.reactive.result.view.ViewResolver;
7577

7678
/**
@@ -226,8 +228,12 @@ public static class EnableWebFluxConfiguration
226228

227229
private final WebFluxProperties webFluxProperties;
228230

229-
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties) {
231+
private final WebFluxRegistrations webFluxRegistrations;
232+
233+
public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
234+
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
230235
this.webFluxProperties = webFluxProperties;
236+
this.webFluxRegistrations = webFluxRegistrations.getIfUnique();
231237
}
232238

233239
@Bean
@@ -249,6 +255,24 @@ public Validator webFluxValidator() {
249255
return ValidatorAdapter.get(getApplicationContext(), getValidator());
250256
}
251257

258+
@Override
259+
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
260+
if (this.webFluxRegistrations != null && this.webFluxRegistrations
261+
.getRequestMappingHandlerAdapter() != null) {
262+
return this.webFluxRegistrations.getRequestMappingHandlerAdapter();
263+
}
264+
return super.createRequestMappingHandlerAdapter();
265+
}
266+
267+
@Override
268+
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
269+
if (this.webFluxRegistrations != null && this.webFluxRegistrations
270+
.getRequestMappingHandlerMapping() != null) {
271+
return this.webFluxRegistrations.getRequestMappingHandlerMapping();
272+
}
273+
return super.createRequestMappingHandlerMapping();
274+
}
275+
252276
}
253277

254278
@Configuration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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+
package org.springframework.boot.autoconfigure.web.reactive;
17+
18+
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
19+
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
20+
21+
/**
22+
* Interface to register key components of the {@link WebFluxAutoConfiguration} in place
23+
* of the default ones provided by Spring WebFlux.
24+
* <p>
25+
* All custom instances are later processed by Boot and Spring WebFlux configurations. A
26+
* single instance of this component should be registered, otherwise making it impossible
27+
* to choose from redundant WebFlux components.
28+
*
29+
* @author Artsiom Yudovin
30+
* @since 2.1.0
31+
* @see org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration.EnableWebFluxConfiguration
32+
*/
33+
public interface WebFluxRegistrations {
34+
35+
/**
36+
* Return the custom {@link RequestMappingHandlerMapping} that should be used and
37+
* processed by the WebFlux configuration.
38+
* @return the custom {@link RequestMappingHandlerMapping} instance
39+
*/
40+
default RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
41+
return null;
42+
}
43+
44+
/**
45+
* Return the custom {@link RequestMappingHandlerAdapter} that should be used and
46+
* processed by the WebFlux configuration.
47+
* @return the custom {@link RequestMappingHandlerAdapter} instance
48+
*/
49+
default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
50+
return null;
51+
}
52+
53+
}

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter;
3434
import org.springframework.context.annotation.Bean;
3535
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.context.annotation.Import;
3637
import org.springframework.core.Ordered;
3738
import org.springframework.core.annotation.Order;
3839
import org.springframework.core.io.ClassPathResource;
@@ -370,6 +371,33 @@ public void hiddenHttpMethodFilterCanBeOverridden() {
370371
});
371372
}
372373

374+
@Test
375+
public void customRequestMappingHandlerMapping() {
376+
this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerMapping.class)
377+
.run((context) -> assertThat(context)
378+
.getBean(RequestMappingHandlerMapping.class)
379+
.isInstanceOf(MyRequestMappingHandlerMapping.class));
380+
}
381+
382+
@Test
383+
public void customRequestMappingHandlerAdapter() {
384+
this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerAdapter.class)
385+
.run((context) -> assertThat(context)
386+
.getBean(RequestMappingHandlerAdapter.class)
387+
.isInstanceOf(MyRequestMappingHandlerAdapter.class));
388+
}
389+
390+
@Test
391+
public void multipleWebFluxRegistrations() {
392+
this.contextRunner.withUserConfiguration(MultipleWebFluxRegistrations.class)
393+
.run((context) -> {
394+
assertThat(context.getBean(RequestMappingHandlerMapping.class))
395+
.isNotInstanceOf(MyRequestMappingHandlerMapping.class);
396+
assertThat(context.getBean(RequestMappingHandlerAdapter.class))
397+
.isNotInstanceOf(MyRequestMappingHandlerAdapter.class);
398+
});
399+
}
400+
373401
@Configuration
374402
protected static class CustomArgumentResolvers {
375403

@@ -485,4 +513,55 @@ public HiddenHttpMethodFilter customHiddenHttpMethodFilter() {
485513

486514
}
487515

516+
@Configuration
517+
static class CustomRequestMappingHandlerAdapter {
518+
519+
@Bean
520+
public WebFluxRegistrations webMvcRegistrationsHandlerAdapter() {
521+
return new WebFluxRegistrations() {
522+
523+
@Override
524+
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
525+
return new WebFluxAutoConfigurationTests.MyRequestMappingHandlerAdapter();
526+
}
527+
528+
};
529+
}
530+
531+
}
532+
533+
private static class MyRequestMappingHandlerAdapter
534+
extends RequestMappingHandlerAdapter {
535+
536+
}
537+
538+
@Configuration
539+
@Import({ WebFluxAutoConfigurationTests.CustomRequestMappingHandlerMapping.class,
540+
WebFluxAutoConfigurationTests.CustomRequestMappingHandlerAdapter.class })
541+
static class MultipleWebFluxRegistrations {
542+
543+
}
544+
545+
@Configuration
546+
static class CustomRequestMappingHandlerMapping {
547+
548+
@Bean
549+
public WebFluxRegistrations webMvcRegistrationsHandlerMapping() {
550+
return new WebFluxRegistrations() {
551+
552+
@Override
553+
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
554+
return new MyRequestMappingHandlerMapping();
555+
}
556+
557+
};
558+
}
559+
560+
}
561+
562+
private static class MyRequestMappingHandlerMapping
563+
extends RequestMappingHandlerMapping {
564+
565+
}
566+
488567
}

0 commit comments

Comments
 (0)