diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessor.java similarity index 58% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessor.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessor.java index 6268e8b67c..4b3e1c143f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 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. @@ -18,31 +18,34 @@ package org.springframework.boot.reactor; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.boot.system.JavaVersion; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.ClassUtils; /** - * {@link EnvironmentPostProcessor} to enable the Reactor Debug Agent if available. + * {@link EnvironmentPostProcessor} to enable the Reactor global features as early as + * possible in the startup process. *

- * The debug agent is enabled by default, unless the - * {@code "spring.reactor.debug-agent.enabled"} configuration property is set to false. We - * are using here an {@link EnvironmentPostProcessor} instead of an auto-configuration - * class to enable the agent as soon as possible during the startup process. + * If the "reactor-tools" dependency is available, the debug agent is enabled by default, + * unless the {@code "spring.reactor.debug-agent.enabled"} configuration property is set + * to false. + *

+ * If the {@code "spring.threads.virtual.enabled"} property is enabled and the current JVM + * is 21 or later, then the Reactor System property is set to configure the Bounded + * Elastic Scheduler to use Virtual Threads globally. * * @author Brian Clozel - * @since 2.2.0 + * @since 3.2.0 */ -public class DebugAgentEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { +public class ReactorEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { private static final String REACTOR_DEBUGAGENT_CLASS = "reactor.tools.agent.ReactorDebugAgent"; - private static final String DEBUGAGENT_ENABLED_CONFIG_KEY = "spring.reactor.debug-agent.enabled"; - @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { if (ClassUtils.isPresent(REACTOR_DEBUGAGENT_CLASS, null)) { - Boolean agentEnabled = environment.getProperty(DEBUGAGENT_ENABLED_CONFIG_KEY, Boolean.class); + Boolean agentEnabled = environment.getProperty("spring.reactor.debug-agent.enabled", Boolean.class); if (agentEnabled != Boolean.FALSE) { try { Class debugAgent = Class.forName(REACTOR_DEBUGAGENT_CLASS); @@ -53,6 +56,10 @@ public class DebugAgentEnvironmentPostProcessor implements EnvironmentPostProces } } } + if (environment.getProperty("spring.threads.virtual.enabled", boolean.class, false) + && JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.TWENTY_ONE)) { + System.setProperty("reactor.schedulers.defaultBoundedElasticOnVirtualThreads", "true"); + } } @Override diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5bc1a19d99..12f70410dd 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -491,7 +491,7 @@ { "name": "spring.reactor.debug-agent.enabled", "type": "java.lang.Boolean", - "sourceType": "org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor", + "sourceType": "org.springframework.boot.reactor.ReactorEnvironmentPostProcessor", "description": "Whether the Reactor Debug Agent should be enabled when reactor-tools is present.", "defaultValue": true }, diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 4641c7b8dd..e6775b7491 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -57,7 +57,7 @@ org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\ org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\ -org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor +org.springframework.boot.reactor.ReactorEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/InstrumentedFluxProvider.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/InstrumentedFluxProvider.java index 2ec6e0c03b..d9382b364b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/InstrumentedFluxProvider.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/InstrumentedFluxProvider.java @@ -22,7 +22,7 @@ import reactor.core.publisher.Flux; * Utility class that should be instrumented by the reactor debug agent. * * @author Brian Clozel - * @see DebugAgentEnvironmentPostProcessorTests + * @see ReactorEnvironmentPostProcessorTests */ class InstrumentedFluxProvider { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessorTests.java similarity index 59% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessorTests.java rename to spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessorTests.java index 87efbcc782..b7aeae2877 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/DebugAgentEnvironmentPostProcessorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessorTests.java @@ -16,8 +16,10 @@ package org.springframework.boot.reactor; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import reactor.core.Scannable; import reactor.core.publisher.Flux; @@ -27,17 +29,18 @@ import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link DebugAgentEnvironmentPostProcessor}. + * Tests for {@link ReactorEnvironmentPostProcessor}. * * @author Brian Clozel */ -@Disabled("We need the not-yet-released reactor-tools 3.4.11 for JDK 17 compatibility") -@ClassPathOverrides("io.projectreactor:reactor-tools:3.4.11") -class DebugAgentEnvironmentPostProcessorTests { + +@ClassPathOverrides("io.projectreactor:reactor-tools:3.5.9") +class ReactorEnvironmentPostProcessorTests { static { MockEnvironment environment = new MockEnvironment(); - DebugAgentEnvironmentPostProcessor postProcessor = new DebugAgentEnvironmentPostProcessor(); + environment.setProperty("spring.threads.virtual.enabled", "true"); + ReactorEnvironmentPostProcessor postProcessor = new ReactorEnvironmentPostProcessor(); postProcessor.postProcessEnvironment(environment, null); } @@ -49,4 +52,21 @@ class DebugAgentEnvironmentPostProcessorTests { .startsWith("Flux.just ⇢ at org.springframework.boot.reactor.InstrumentedFluxProvider.newFluxJust"); } + @Test + @EnabledForJreRange(max = JRE.JAVA_20) + void shouldNotEnableVirtualThreads() { + assertThat(System.getProperty("reactor.schedulers.defaultBoundedElasticOnVirtualThreads")).isNotEqualTo("true"); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_21) + void shouldEnableVirtualThreads() { + assertThat(System.getProperty("reactor.schedulers.defaultBoundedElasticOnVirtualThreads")).isEqualTo("true"); + } + + @AfterEach + void cleanup() { + System.setProperty("reactor.schedulers.defaultBoundedElasticOnVirtualThreads", "false"); + } + }