From fe1011c23d500a6fd30eacb05051089bac978808 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 30 Mar 2021 18:05:25 +0200 Subject: [PATCH] Add Netty memory leak detection config property This commit adds a new `spring.netty.leak-detection` configuration property that selects the level of memory leak detection for the Netty engine. This configuration is applied statically to Netty; this means all (non-shaded) Netty usages as client or server will be impacted by this change. Developers might use this property during development or tests to find causes of memory leaks when dealing with Netty buffers. Closes gh-14338 --- .../DocumentConfigurationProperties.java | 2 +- .../netty/NettyAutoConfiguration.java | 45 ++++++++++++ .../autoconfigure/netty/NettyProperties.java | 69 +++++++++++++++++++ .../autoconfigure/netty/package-info.java | 20 ++++++ ...itional-spring-configuration-metadata.json | 4 ++ .../main/resources/META-INF/spring.factories | 1 + .../netty/NettyAutoConfigurationTests.java | 46 +++++++++++++ 7 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfigurationTests.java diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java index 86ae8f05b0..a0931d49d3 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java @@ -72,7 +72,7 @@ public class DocumentConfigurationProperties extends DefaultTask { .addSection("mail").withKeyPrefixes("spring.mail", "spring.sendgrid").addSection("cache") .withKeyPrefixes("spring.cache").addSection("server").withKeyPrefixes("server").addSection("web") .withKeyPrefixes("spring.hateoas", "spring.http", "spring.servlet", "spring.jersey", "spring.mvc", - "spring.resources", "spring.session", "spring.web", "spring.webflux") + "spring.netty", "spring.resources", "spring.session", "spring.web", "spring.webflux") .addSection("json").withKeyPrefixes("spring.jackson", "spring.gson").addSection("rsocket") .withKeyPrefixes("spring.rsocket").addSection("templating") .withKeyPrefixes("spring.freemarker", "spring.groovy", "spring.mustache", "spring.thymeleaf") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfiguration.java new file mode 100644 index 0000000000..c4c8298902 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfiguration.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2021 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.netty; + +import io.netty.util.NettyRuntime; +import io.netty.util.ResourceLeakDetector; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Netty. + * + * @author Brian Clozel + * @since 2.5.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(NettyRuntime.class) +@EnableConfigurationProperties(NettyProperties.class) +public class NettyAutoConfiguration { + + public NettyAutoConfiguration(NettyProperties properties) { + if (properties.getLeakDetection() != null) { + NettyProperties.LeakDetection leakDetection = properties.getLeakDetection(); + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.valueOf(leakDetection.name())); + } + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyProperties.java new file mode 100644 index 0000000000..55bdceef8a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/NettyProperties.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2021 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.netty; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties @ConfigurationProperties} for the Netty engine. + *

+ * These properties apply globally to the Netty library, used as a client or a server. + * + * @author Brian Clozel + * @since 2.5.0 + */ +@ConfigurationProperties(prefix = "spring.netty") +public class NettyProperties { + + /** + * Level of leak detection for reference-counted buffers. + */ + private LeakDetection leakDetection = LeakDetection.DISABLED; + + public LeakDetection getLeakDetection() { + return this.leakDetection; + } + + public void setLeakDetection(LeakDetection leakDetection) { + this.leakDetection = leakDetection; + } + + public enum LeakDetection { + + /** + * Disable leak detection completely. + */ + DISABLED, + + /** + * Detect leaks for 1% of buffers. + */ + SIMPLE, + + /** + * Detect leaks for 1% of buffers and track where they were accessed. + */ + ADVANCED, + + /** + * Detect leaks for 100% of buffers and track where they were accessed. + */ + PARANOID + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/package-info.java new file mode 100644 index 0000000000..0784c137ec --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/netty/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2021 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 the Netty library. + */ +package org.springframework.boot.autoconfigure.netty; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 3298f297dd..ad42df86ff 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1770,6 +1770,10 @@ "name": "spring.webservices.wsdl-locations", "type": "java.util.List", "description": "Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans." + }, + { + "name": "spring.netty.leak-detection", + "defaultValue": "disabled" } ], "hints": [ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 5a0f37feb8..a438278ef2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -105,6 +105,7 @@ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\ +org.springframework.boot.autoconfigure.netty.NettyAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfigurationTests.java new file mode 100644 index 0000000000..609cd3cbc4 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/netty/NettyAutoConfigurationTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2021 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.netty; + +import io.netty.util.ResourceLeakDetector; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link NettyAutoConfiguration}. + * + * @author Brian Clozel + */ +public class NettyAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(NettyAutoConfiguration.class)); + + @Test + void leakDetectionShouldBeConfigured() { + this.contextRunner.withPropertyValues("spring.netty.leak-detection=paranoid").run((context) -> { + assertThat(ResourceLeakDetector.getLevel()).isEqualTo(ResourceLeakDetector.Level.PARANOID); + // reset configuration for the following tests. + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); + }); + } + +}