Only configure WebFlux blocking executor when using virtual threads

Fixes gh-39469
This commit is contained in:
Andy Wilkinson 2024-02-09 18:25:51 +00:00
parent 720e9cef16
commit 256f9fe83a
2 changed files with 38 additions and 12 deletions

View File

@ -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.
@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
@ -55,6 +56,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionService;
@ -149,6 +151,8 @@ public class WebFluxAutoConfiguration {
private static final Log logger = LogFactory.getLog(WebFluxConfig.class);
private final Environment environment;
private final Resources resourceProperties;
private final WebFluxProperties webFluxProperties;
@ -163,11 +167,12 @@ public class WebFluxAutoConfiguration {
private final ObjectProvider<ViewResolver> viewResolvers;
public WebFluxConfig(WebProperties webProperties, WebFluxProperties webFluxProperties,
public WebFluxConfig(Environment environment, WebProperties webProperties, WebFluxProperties webFluxProperties,
ListableBeanFactory beanFactory, ObjectProvider<HandlerMethodArgumentResolver> resolvers,
ObjectProvider<CodecCustomizer> codecCustomizers,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizer,
ObjectProvider<ViewResolver> viewResolvers) {
this.environment = environment;
this.resourceProperties = webProperties.getResources();
this.webFluxProperties = webFluxProperties;
this.beanFactory = beanFactory;
@ -189,7 +194,8 @@ public class WebFluxAutoConfiguration {
@Override
public void configureBlockingExecution(BlockingExecutionConfigurer configurer) {
if (this.beanFactory.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {
if (Threading.VIRTUAL.isActive(this.environment) && this.beanFactory
.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {
Object taskExecutor = this.beanFactory
.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
if (taskExecutor instanceof AsyncTaskExecutor asyncTaskExecutor) {

View File

@ -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.
@ -39,6 +39,8 @@ import org.aspectj.lang.annotation.Aspect;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -687,8 +689,20 @@ class WebFluxAutoConfigurationTests {
}
@Test
void asyncTaskExecutorWithApplicationTaskExecutor() {
void asyncTaskExecutorWithPlatformThreadsAndApplicationTaskExecutor() {
this.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasSingleBean(AsyncTaskExecutor.class);
assertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting("scheduler.executor")
.isNull();
});
}
@Test
@EnabledForJreRange(min = JRE.JAVA_21)
void asyncTaskExecutorWithVirtualThreadsAndApplicationTaskExecutor() {
this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true")
.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasSingleBean(AsyncTaskExecutor.class);
assertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting("scheduler.executor")
@ -697,8 +711,10 @@ class WebFluxAutoConfigurationTests {
}
@Test
void asyncTaskExecutorWithNonMatchApplicationTaskExecutorBean() {
this.contextRunner.withUserConfiguration(CustomApplicationTaskExecutorConfig.class)
@EnabledForJreRange(min = JRE.JAVA_21)
void asyncTaskExecutorWithVirtualThreadsAndNonMatchApplicationTaskExecutorBean() {
this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true")
.withUserConfiguration(CustomApplicationTaskExecutorConfig.class)
.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
.run((context) -> {
assertThat(context).doesNotHaveBean(AsyncTaskExecutor.class);
@ -708,8 +724,10 @@ class WebFluxAutoConfigurationTests {
}
@Test
void asyncTaskExecutorWithWebFluxConfigurerCanOverrideExecutor() {
this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class)
@EnabledForJreRange(min = JRE.JAVA_21)
void asyncTaskExecutorWithVirtualThreadsAndWebFluxConfigurerCanOverrideExecutor() {
this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true")
.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class)
.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))
.extracting("scheduler.executor")
@ -717,13 +735,15 @@ class WebFluxAutoConfigurationTests {
}
@Test
void asyncTaskExecutorWithCustomNonApplicationTaskExecutor() {
this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfig.class)
@EnabledForJreRange(min = JRE.JAVA_21)
void asyncTaskExecutorWithVirtualThreadsAndCustomNonApplicationTaskExecutor() {
this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true")
.withUserConfiguration(CustomAsyncTaskExecutorConfig.class)
.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasSingleBean(AsyncTaskExecutor.class);
assertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting("scheduler.executor")
.isNotSameAs(context.getBean("customTaskExecutor"));
.isNull();
});
}