From 2a843d1853f4dc8352da206428c436496c7faeba Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 17 Jan 2023 13:08:16 +0100 Subject: [PATCH] Set Reactor Netty's shutdownQuietPeriod to 0 when using devtools See gh-33855 --- .../ReactorNettyConfigurationProperties.java | 45 ++++++++++++++++ .../netty/ReactorNettyConfigurations.java | 53 +++++++++++++++++++ .../reactor/netty/package-info.java | 20 +++++++ .../RSocketServerAutoConfiguration.java | 11 ++-- ...ReactiveWebServerFactoryConfiguration.java | 11 ++-- .../ClientHttpConnectorConfiguration.java | 11 ++-- ...ntHttpConnectorAutoConfigurationTests.java | 4 +- .../env/devtools-property-defaults.properties | 1 + 8 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurationProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurations.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/package-info.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurationProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurationProperties.java new file mode 100644 index 0000000000..b7e68516a6 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurationProperties.java @@ -0,0 +1,45 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.reactor.netty; + +import java.time.Duration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Reactor Netty configuration. + * + * @author Moritz Halbritter + * @since 2.7.9 + */ +@ConfigurationProperties(prefix = "spring.reactor.netty") +public class ReactorNettyConfigurationProperties { + + /** + * Configure the amount of time to wait before shutting down resources. + */ + private Duration shutdownQuietPeriod; + + public Duration getShutdownQuietPeriod() { + return this.shutdownQuietPeriod; + } + + public void setShutdownQuietPeriod(Duration shutdownQuietPeriod) { + this.shutdownQuietPeriod = shutdownQuietPeriod; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurations.java new file mode 100644 index 0000000000..64246cb36f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/ReactorNettyConfigurations.java @@ -0,0 +1,53 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.reactor.netty; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ReactorResourceFactory; + +/** + * Configurations for Reactor Netty. Those should be {@code @Import} in a regular + * auto-configuration class. + * + * @author Moritz Halbritter + * @since 2.7.9 + */ +public final class ReactorNettyConfigurations { + + private ReactorNettyConfigurations() { + } + + @Configuration(proxyBeanMethods = false) + @EnableConfigurationProperties(ReactorNettyConfigurationProperties.class) + public static class ReactorResourceFactoryConfiguration { + + @Bean + @ConditionalOnMissingBean + ReactorResourceFactory reactorResourceFactory(ReactorNettyConfigurationProperties configurationProperties) { + ReactorResourceFactory reactorResourceFactory = new ReactorResourceFactory(); + if (configurationProperties.getShutdownQuietPeriod() != null) { + reactorResourceFactory.setShutdownQuietPeriod(configurationProperties.getShutdownQuietPeriod()); + } + return reactorResourceFactory; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/package-info.java new file mode 100644 index 0000000000..e9842ee9fc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/netty/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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. + */ + +/** + * Auto-configuration for Reactor Netty. + */ +package org.springframework.boot.autoconfigure.reactor.netty; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfiguration.java index f8e33e21ad..dd5b8c13ac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigurations; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.rsocket.context.RSocketServerBootstrap; @@ -41,6 +42,7 @@ import org.springframework.boot.rsocket.server.RSocketServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.client.reactive.ReactorResourceFactory; import org.springframework.messaging.rsocket.RSocketStrategies; @@ -79,14 +81,9 @@ public class RSocketServerAutoConfiguration { @ConditionalOnProperty(prefix = "spring.rsocket.server", name = "port") @ConditionalOnClass(ReactorResourceFactory.class) @Configuration(proxyBeanMethods = false) + @Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class) static class EmbeddedServerConfiguration { - @Bean - @ConditionalOnMissingBean - ReactorResourceFactory reactorResourceFactory() { - return new ReactorResourceFactory(); - } - @Bean @ConditionalOnMissingBean RSocketServerFactory rSocketServerFactory(RSocketProperties properties, ReactorResourceFactory resourceFactory, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java index 6ec994d776..e76489d901 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.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. @@ -25,6 +25,7 @@ import reactor.netty.http.server.HttpServer; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigurations; import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; @@ -39,6 +40,7 @@ import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerF import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.http.client.reactive.JettyResourceFactory; import org.springframework.http.client.reactive.ReactorResourceFactory; @@ -57,14 +59,9 @@ abstract class ReactiveWebServerFactoryConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ReactiveWebServerFactory.class) @ConditionalOnClass({ HttpServer.class }) + @Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class) static class EmbeddedNetty { - @Bean - @ConditionalOnMissingBean - ReactorResourceFactory reactorServerResourceFactory() { - return new ReactorResourceFactory(); - } - @Bean NettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory, ObjectProvider routes, ObjectProvider serverCustomizers) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java index 7e65578a57..09a92996a7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 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. @@ -24,8 +24,10 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.reactor.netty.ReactorNettyConfigurations; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector; @@ -48,14 +50,9 @@ class ClientHttpConnectorConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(reactor.netty.http.client.HttpClient.class) @ConditionalOnMissingBean(ClientHttpConnector.class) + @Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class) static class ReactorNetty { - @Bean - @ConditionalOnMissingBean - ReactorResourceFactory reactorClientResourceFactory() { - return new ReactorResourceFactory(); - } - @Bean @Lazy ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory reactorResourceFactory, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java index e329138a31..7010c0cbb8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 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. @@ -56,7 +56,7 @@ class ClientHttpConnectorAutoConfigurationTests { BeanDefinition connectorDefinition = context.getBeanFactory() .getBeanDefinition("reactorClientHttpConnector"); assertThat(connectorDefinition.isLazyInit()).isTrue(); - assertThat(context).hasBean("reactorClientResourceFactory"); + assertThat(context).hasSingleBean(ReactorResourceFactory.class); }); } diff --git a/spring-boot-project/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/env/devtools-property-defaults.properties b/spring-boot-project/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/env/devtools-property-defaults.properties index 053817b051..c691328709 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/env/devtools-property-defaults.properties +++ b/spring-boot-project/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/env/devtools-property-defaults.properties @@ -13,3 +13,4 @@ spring.template.provider.cache=false spring.thymeleaf.cache=false spring.web.resources.cache.period=0 spring.web.resources.chain.cache=false +spring.reactor.netty.shutdown-quiet-period=0s