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:
		
							parent
							
								
									ba2f2a3727
								
							
						
					
					
						commit
						1c224e5fbb
					
				|  | @ -71,6 +71,8 @@ import org.springframework.web.reactive.resource.ResourceResolver; | ||||||
| import org.springframework.web.reactive.resource.VersionResourceResolver; | import org.springframework.web.reactive.resource.VersionResourceResolver; | ||||||
| import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; | 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.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; | import org.springframework.web.reactive.result.view.ViewResolver; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -226,8 +228,12 @@ public class WebFluxAutoConfiguration { | ||||||
| 
 | 
 | ||||||
| 		private final WebFluxProperties webFluxProperties; | 		private final WebFluxProperties webFluxProperties; | ||||||
| 
 | 
 | ||||||
| 		public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties) { | 		private final WebFluxRegistrations webFluxRegistrations; | ||||||
|  | 
 | ||||||
|  | 		public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties, | ||||||
|  | 				ObjectProvider<WebFluxRegistrations> webFluxRegistrations) { | ||||||
| 			this.webFluxProperties = webFluxProperties; | 			this.webFluxProperties = webFluxProperties; | ||||||
|  | 			this.webFluxRegistrations = webFluxRegistrations.getIfUnique(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Bean | 		@Bean | ||||||
|  | @ -249,6 +255,24 @@ public class WebFluxAutoConfiguration { | ||||||
| 			return ValidatorAdapter.get(getApplicationContext(), getValidator()); | 			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 | 	@Configuration | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -33,6 +33,7 @@ import org.springframework.boot.web.codec.CodecCustomizer; | ||||||
| import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; | import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
| import org.springframework.core.Ordered; | import org.springframework.core.Ordered; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
| import org.springframework.core.io.ClassPathResource; | 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 | 	@Configuration | ||||||
| 	protected static class CustomArgumentResolvers { | 	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 { | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue