-
Notifications
You must be signed in to change notification settings - Fork 38.4k
Provide equivalent of @EnableWebFlux and @EnableWebMvc for the RouterFunction approach #25497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This (Spring-Boot style) works for me, but I can't say if it is more or less complicated than it needs to be. It's a drop-in replacement for @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnWebApplication(type = Type.REACTIVE)
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
ValidationAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class RouterFunctionAutoConfiguration {
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.webflux.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
@Configuration(proxyBeanMethods = false)
public static class WelcomePageConfiguration {
@Bean
public RouterFunctionMapping welcomePageRouterFunctionMapping(ApplicationContext applicationContext,
WebFluxProperties webFluxProperties, ResourceProperties resourceProperties) {
WelcomePageRouterFunctionFactory factory = new WelcomePageRouterFunctionFactory(
new TemplateAvailabilityProviders(applicationContext), applicationContext,
resourceProperties.getStaticLocations(), webFluxProperties.getStaticPathPattern());
RouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();
if (routerFunction != null) {
RouterFunctionMapping routerFunctionMapping = new RouterFunctionMapping(routerFunction);
routerFunctionMapping.setOrder(1);
return routerFunctionMapping;
}
return null;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
public static class EnableFunctionalConfiguration implements ApplicationContextAware {
private WebFluxAutoConfiguration.EnableWebFluxConfiguration delegate;
@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
delegate.setApplicationContext(applicationContext);
}
public EnableFunctionalConfiguration(WebFluxProperties webFluxProperties,
ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
delegate = new WebFluxAutoConfiguration.EnableWebFluxConfiguration(webFluxProperties, webFluxRegistrations);
}
@Bean
public DispatcherHandler webHandler() {
return delegate.webHandler();
}
@Bean
@Order(0)
public WebExceptionHandler responseStatusExceptionHandler() {
return delegate.responseStatusExceptionHandler();
}
@Bean
public RequestedContentTypeResolver webFluxContentTypeResolver() {
return delegate.webFluxContentTypeResolver();
}
@Bean
public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) {
return delegate.routerFunctionMapping(serverCodecConfigurer);
}
@Bean
public ResourceUrlProvider resourceUrlProvider() {
return delegate.resourceUrlProvider();
}
@Bean
public ServerCodecConfigurer serverCodecConfigurer() {
return delegate.serverCodecConfigurer();
}
@Bean
public LocaleContextResolver localeContextResolver() {
return delegate.localeContextResolver();
}
@Bean
public ReactiveAdapterRegistry webFluxAdapterRegistry() {
return delegate.webFluxAdapterRegistry();
}
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return delegate.handlerFunctionAdapter();
}
@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return delegate.simpleHandlerAdapter();
}
@Bean
public ServerResponseResultHandler serverResponseResultHandler(ServerCodecConfigurer serverCodecConfigurer) {
return delegate.serverResponseResultHandler(serverCodecConfigurer);
}
@Bean
public FormattingConversionService webFluxConversionService() {
return delegate.webFluxConversionService();
}
@Bean
public Validator webFluxValidator() {
return delegate.webFluxValidator();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
@Bean
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
}
}
} and the MVC version: @Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
@EnableConfigurationProperties({ResourceProperties.class, WebMvcProperties.class})
public class RouterFunctionAutoConfiguration {
private static final String[] SERVLET_LOCATIONS = { "/" };
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
@Bean
@ConditionalOnMissingBean(FormContentFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true)
public OrderedFormContentFilter formContentFilter() {
return new OrderedFormContentFilter();
}
static String[] getResourceLocations(String[] staticLocations) {
String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
return locations;
}
@Configuration(proxyBeanMethods = false)
public static class EnableFunctionalConfiguration implements ResourceLoaderAware {
private WebMvcAutoConfiguration.EnableWebMvcConfiguration delegate;
@Nullable
private List<Object> interceptors;
public EnableFunctionalConfiguration(ResourceProperties resourceProperties,
ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
delegate = new WebMvcAutoConfiguration.EnableWebMvcConfiguration(resourceProperties, mvcPropertiesProvider, mvcRegistrationsProvider, beanFactory);
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
delegate.setResourceLoader(resourceLoader);
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
return delegate.welcomePageHandlerMapping(applicationContext, mvcConversionService, mvcResourceUrlProvider);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale", matchIfMissing = true)
public LocaleResolver localeResolver() {
return delegate.localeResolver();
}
@Bean
public FormattingConversionService mvcConversionService() {
return delegate.mvcConversionService();
}
@Bean
public Validator mvcValidator() {
return delegate.mvcValidator();
}
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
return delegate.mvcContentNegotiationManager();
}
@Bean
public UrlPathHelper mvcUrlPathHelper() {
return delegate.mvcUrlPathHelper();
}
@Bean
public PathMatcher mvcPathMatcher() {
return delegate.mvcPathMatcher();
}
@Bean
public RouterFunctionMapping routerFunctionMapping(
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
return delegate.routerFunctionMapping(conversionService, resourceUrlProvider);
}
@Bean
@Nullable
public HandlerMapping resourceHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
return delegate.resourceHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider);
}
@Bean
public ResourceUrlProvider mvcResourceUrlProvider() {
return delegate.mvcResourceUrlProvider();
}
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return delegate.handlerFunctionAdapter();
}
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return delegate.httpRequestHandlerAdapter();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
return delegate.handlerExceptionResolver(contentNegotiationManager);
}
@Bean
public ViewResolver mvcViewResolver(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
return delegate.mvcViewResolver(contentNegotiationManager);
}
@Bean
@Lazy
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
return delegate.mvcHandlerMappingIntrospector();
}
@Bean
public ThemeResolver themeResolver() {
return delegate.themeResolver();
}
@Bean
public FlashMapManager flashMapManager() {
return delegate.flashMapManager();
}
@Bean
public RequestToViewNameTranslator viewNameTranslator() {
return delegate.viewNameTranslator();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
@Bean
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
}
}
} |
After a team related discussion, we think this is an area where there could be interesting options to explore in the future, but I am going to decline this specific enhancement request for several reasons:
|
If a user only provides
RouterFunction
endpoints it's a shame to load up the application context with loads of annotation-processing (RequestMappingHandlerMapping
etc.). But everything happens in the same place right now.See spring-projects/spring-boot#22314.
The text was updated successfully, but these errors were encountered: