From e5a09b3b319777fae2b4ae07edd28918d7fabc9a Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Fri, 18 Mar 2022 09:35:29 -0500 Subject: [PATCH 1/2] Apply unique-names consistently in JmxAutoConfiguration Ensure that the `spring.jmx.unique-names` property is applied to the auto-configured `MBeanExporter` as well as the `ObjectNamingStrategy`. Fixes gh-29968 --- .../jmx/JmxAutoConfiguration.java | 3 + .../jmx/JmxAutoConfigurationTests.java | 131 ++++++++---------- 2 files changed, 59 insertions(+), 75 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java index 75e76d1f54..33f15e5af4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.util.StringUtils; * @author Christian Dupuis * @author Madhura Bhave * @author Artsiom Yudovin + * @author Scott Frederick * @since 1.0.0 */ @AutoConfiguration @@ -72,6 +73,8 @@ public class JmxAutoConfiguration { if (StringUtils.hasLength(serverBean)) { exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class)); } + boolean uniqueNames = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false); + exporter.setEnsureUniqueRuntimeObjectNames(uniqueNames); return exporter; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java index 5caddce419..ce11238e44 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -16,12 +16,12 @@ package org.springframework.boot.autoconfigure.jmx; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.boot.context.annotation.UserConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -32,114 +32,95 @@ import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.naming.MetadataNamingStrategy; -import org.springframework.mock.env.MockEnvironment; +import org.springframework.jmx.export.naming.ObjectNamingStrategy; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link JmxAutoConfiguration}. * * @author Christian Dupuis * @author Artsiom Yudovin + * @author Scott Frederick */ class JmxAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @AfterEach - void tearDown() { - if (this.context != null) { - this.context.close(); - if (this.context.getParent() != null) { - ((ConfigurableApplicationContext) this.context.getParent()).close(); - } - } - } + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class)); @Test void testDefaultMBeanExport() { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(JmxAutoConfiguration.class); - this.context.refresh(); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(MBeanExporter.class)); + this.contextRunner.run((context) -> { + assertThat(context).doesNotHaveBean(MBeanExporter.class); + assertThat(context).doesNotHaveBean(ObjectNamingStrategy.class); + }); } @Test - void testEnabledMBeanExport() { - MockEnvironment env = new MockEnvironment(); - env.setProperty("spring.jmx.enabled", "true"); - this.context = new AnnotationConfigApplicationContext(); - this.context.setEnvironment(env); - this.context.register(JmxAutoConfiguration.class); - this.context.refresh(); - assertThat(this.context.getBean(MBeanExporter.class)).isNotNull(); + void testDisabledMBeanExport() { + this.contextRunner.withPropertyValues("spring.jmx.enabled=false").run((context) -> { + assertThat(context).doesNotHaveBean(MBeanExporter.class); + assertThat(context).doesNotHaveBean(ObjectNamingStrategy.class); + }); } @Test - void testDisabledMBeanExport() { - MockEnvironment env = new MockEnvironment(); - env.setProperty("spring.jmx.enabled", "false"); - this.context = new AnnotationConfigApplicationContext(); - this.context.setEnvironment(env); - this.context.register(TestConfiguration.class, JmxAutoConfiguration.class); - this.context.refresh(); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(MBeanExporter.class)); + void testEnabledMBeanExport() { + this.contextRunner.withPropertyValues("spring.jmx.enabled=true").run((context) -> { + assertThat(context).hasSingleBean(MBeanExporter.class); + assertThat(context).hasSingleBean(ParentAwareNamingStrategy.class); + MBeanExporter exporter = context.getBean(MBeanExporter.class); + assertThat(exporter).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", false); + MetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter, + "namingStrategy"); + assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", false); + }); } @Test void testDefaultDomainConfiguredOnMBeanExport() { - MockEnvironment env = new MockEnvironment(); - env.setProperty("spring.jmx.enabled", "true"); - env.setProperty("spring.jmx.default-domain", "my-test-domain"); - env.setProperty("spring.jmx.unique-names", "true"); - this.context = new AnnotationConfigApplicationContext(); - this.context.setEnvironment(env); - this.context.register(TestConfiguration.class, JmxAutoConfiguration.class); - this.context.refresh(); - MBeanExporter mBeanExporter = this.context.getBean(MBeanExporter.class); - assertThat(mBeanExporter).isNotNull(); - MetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(mBeanExporter, - "namingStrategy"); - assertThat(naming).hasFieldOrPropertyWithValue("defaultDomain", "my-test-domain"); - assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true); + this.contextRunner.withPropertyValues("spring.jmx.enabled=true", "spring.jmx.default-domain=my-test-domain", + "spring.jmx.unique-names=true").run((context) -> { + assertThat(context).hasSingleBean(MBeanExporter.class); + MBeanExporter exporter = context.getBean(MBeanExporter.class); + assertThat(exporter).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true); + MetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter, + "namingStrategy"); + assertThat(naming).hasFieldOrPropertyWithValue("defaultDomain", "my-test-domain"); + assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true); + }); } @Test void testBasicParentContext() { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(JmxAutoConfiguration.class); - this.context.refresh(); - AnnotationConfigApplicationContext parent = this.context; - this.context = new AnnotationConfigApplicationContext(); - this.context.setParent(parent); - this.context.register(JmxAutoConfiguration.class); - this.context.refresh(); + try (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) { + parent.register(JmxAutoConfiguration.class); + parent.refresh(); + this.contextRunner.withParent(parent).run((context) -> assertThat(context.isRunning())); + } } @Test void testParentContext() { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(JmxAutoConfiguration.class, TestConfiguration.class); - this.context.refresh(); - AnnotationConfigApplicationContext parent = this.context; - this.context = new AnnotationConfigApplicationContext(); - this.context.setParent(parent); - this.context.register(JmxAutoConfiguration.class, TestConfiguration.class); - this.context.refresh(); + try (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) { + parent.register(JmxAutoConfiguration.class, TestConfiguration.class); + parent.refresh(); + this.contextRunner.withParent(parent).withConfiguration(UserConfigurations.of(TestConfiguration.class)) + .run((context) -> assertThat(context.isRunning())); + } } @Test void customJmxDomain() { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(CustomJmxDomainConfiguration.class, JmxAutoConfiguration.class, - IntegrationAutoConfiguration.class); - this.context.refresh(); - IntegrationMBeanExporter mbeanExporter = this.context.getBean(IntegrationMBeanExporter.class); - assertThat(mbeanExporter).hasFieldOrPropertyWithValue("domain", "foo.my"); + this.contextRunner.withConfiguration(UserConfigurations.of(CustomJmxDomainConfiguration.class)) + .withConfiguration( + AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class)) + .run((context) -> { + assertThat(context).hasSingleBean(IntegrationMBeanExporter.class); + IntegrationMBeanExporter exporter = context.getBean(IntegrationMBeanExporter.class); + assertThat(exporter).hasFieldOrPropertyWithValue("domain", "foo.my"); + }); } @Configuration(proxyBeanMethods = false) From a14f3ed2006b76d8dadef6e71e0a2ce94b5efbfd Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Fri, 18 Mar 2022 14:40:22 -0500 Subject: [PATCH 2/2] Use a ConfigurationProperties class for JMX properties Closes gh-30327 --- .../jmx/DefaultEndpointObjectNameFactory.java | 22 ++--- .../jmx/JmxEndpointAutoConfiguration.java | 15 ++-- ...DefaultEndpointObjectNameFactoryTests.java | 12 +-- .../IntegrationAutoConfiguration.java | 11 ++- .../jmx/JmxAutoConfiguration.java | 19 ++--- .../boot/autoconfigure/jmx/JmxProperties.java | 82 +++++++++++++++++++ ...itional-spring-configuration-metadata.json | 23 ------ 7 files changed, 122 insertions(+), 62 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxProperties.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java index b6b02ea19f..eac4b9403c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -22,7 +22,7 @@ import javax.management.ObjectName; import org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; -import org.springframework.core.env.Environment; +import org.springframework.boot.autoconfigure.jmx.JmxProperties; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -37,21 +37,18 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { private final JmxEndpointProperties properties; - private final Environment environment; + private final JmxProperties jmxProperties; private final MBeanServer mBeanServer; private final String contextId; - private final boolean uniqueNames; - - DefaultEndpointObjectNameFactory(JmxEndpointProperties properties, Environment environment, MBeanServer mBeanServer, - String contextId) { + DefaultEndpointObjectNameFactory(JmxEndpointProperties properties, JmxProperties jmxProperties, + MBeanServer mBeanServer, String contextId) { this.properties = properties; - this.environment = environment; + this.jmxProperties = jmxProperties; this.mBeanServer = mBeanServer; this.contextId = contextId; - this.uniqueNames = environment.getProperty("spring.jmx.unique-names", Boolean.class, false); } @Override @@ -63,7 +60,7 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { if (this.mBeanServer != null && hasMBean(baseName)) { builder.append(",context=").append(this.contextId); } - if (this.uniqueNames) { + if (this.jmxProperties.isUniqueNames()) { String identity = ObjectUtils.getIdentityHexString(endpoint); builder.append(",identity=").append(identity); } @@ -75,7 +72,10 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { if (StringUtils.hasText(this.properties.getDomain())) { return this.properties.getDomain(); } - return this.environment.getProperty("spring.jmx.default-domain", "org.springframework.boot"); + if (StringUtils.hasText(this.jmxProperties.getDefaultDomain())) { + return this.jmxProperties.getDefaultDomain(); + } + return "org.springframework.boot"; } private boolean hasMBean(String baseObjectName) throws MalformedObjectNameException { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java index 9c3ae54857..d267edee0c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java @@ -44,10 +44,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; +import org.springframework.boot.autoconfigure.jmx.JmxProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.core.env.Environment; import org.springframework.util.ObjectUtils; /** @@ -60,7 +60,7 @@ import org.springframework.util.ObjectUtils; * @since 2.0.0 */ @AutoConfiguration(after = { JmxAutoConfiguration.class, EndpointAutoConfiguration.class }) -@EnableConfigurationProperties(JmxEndpointProperties.class) +@EnableConfigurationProperties({ JmxEndpointProperties.class, JmxProperties.class }) @ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true") public class JmxEndpointAutoConfiguration { @@ -68,9 +68,13 @@ public class JmxEndpointAutoConfiguration { private final JmxEndpointProperties properties; - public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, JmxEndpointProperties properties) { + private final JmxProperties jmxProperties; + + public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, JmxEndpointProperties properties, + JmxProperties jmxProperties) { this.applicationContext = applicationContext; this.properties = properties; + this.jmxProperties = jmxProperties; } @Bean @@ -85,10 +89,9 @@ public class JmxEndpointAutoConfiguration { @Bean @ConditionalOnMissingBean(EndpointObjectNameFactory.class) - public DefaultEndpointObjectNameFactory endpointObjectNameFactory(MBeanServer mBeanServer, - Environment environment) { + public DefaultEndpointObjectNameFactory endpointObjectNameFactory(MBeanServer mBeanServer) { String contextId = ObjectUtils.getIdentityHexString(this.applicationContext); - return new DefaultEndpointObjectNameFactory(this.properties, environment, mBeanServer, contextId); + return new DefaultEndpointObjectNameFactory(this.properties, this.jmxProperties, mBeanServer, contextId); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java index e9f0663619..45c1804058 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.endpoint.EndpointId; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; -import org.springframework.mock.env.MockEnvironment; +import org.springframework.boot.autoconfigure.jmx.JmxProperties; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -40,10 +40,10 @@ import static org.mockito.Mockito.mock; */ class DefaultEndpointObjectNameFactoryTests { - private final MockEnvironment environment = new MockEnvironment(); - private final JmxEndpointProperties properties = new JmxEndpointProperties(); + private final JmxProperties jmxProperties = new JmxProperties(); + private final MBeanServer mBeanServer = mock(MBeanServer.class); private String contextId; @@ -69,7 +69,7 @@ class DefaultEndpointObjectNameFactoryTests { @Test void generateObjectNameWithUniqueNames() { - this.environment.setProperty("spring.jmx.unique-names", "true"); + this.jmxProperties.setUniqueNames(true); assertUniqueObjectName(); } @@ -103,7 +103,7 @@ class DefaultEndpointObjectNameFactoryTests { private ObjectName generateObjectName(ExposableJmxEndpoint endpoint) { try { - return new DefaultEndpointObjectNameFactory(this.properties, this.environment, this.mBeanServer, + return new DefaultEndpointObjectNameFactory(this.properties, this.jmxProperties, this.mBeanServer, this.contextId).getObjectName(endpoint); } catch (MalformedObjectNameException ex) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 9456cb3547..fea498382c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandi import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; +import org.springframework.boot.autoconfigure.jmx.JmxProperties; import org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration; import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition; import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; @@ -46,7 +47,6 @@ 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.env.Environment; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.config.EnableIntegrationManagement; import org.springframework.integration.config.IntegrationManagementConfigurer; @@ -84,7 +84,7 @@ import org.springframework.util.StringUtils; @AutoConfiguration(after = { DataSourceAutoConfiguration.class, JmxAutoConfiguration.class, TaskSchedulingAutoConfiguration.class }) @ConditionalOnClass(EnableIntegration.class) -@EnableConfigurationProperties(IntegrationProperties.class) +@EnableConfigurationProperties({ IntegrationProperties.class, JmxProperties.class }) public class IntegrationAutoConfiguration { @Bean(name = IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME) @@ -186,14 +186,13 @@ public class IntegrationAutoConfiguration { protected static class IntegrationJmxConfiguration { @Bean - public IntegrationMBeanExporter integrationMbeanExporter(BeanFactory beanFactory, Environment environment) { + public IntegrationMBeanExporter integrationMbeanExporter(BeanFactory beanFactory, JmxProperties properties) { IntegrationMBeanExporter exporter = new IntegrationMBeanExporter(); - String defaultDomain = environment.getProperty("spring.jmx.default-domain"); + String defaultDomain = properties.getDefaultDomain(); if (StringUtils.hasLength(defaultDomain)) { exporter.setDefaultDomain(defaultDomain); } - String serverBean = environment.getProperty("spring.jmx.server", "mbeanServer"); - exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class)); + exporter.setServer(beanFactory.getBean(properties.getServer(), MBeanServer.class)); return exporter; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java index 33f15e5af4..4df5e6570c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java @@ -25,11 +25,11 @@ 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.SearchStrategy; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.EnableMBeanExport; import org.springframework.context.annotation.MBeanExportConfiguration.SpecificPlatform; import org.springframework.context.annotation.Primary; -import org.springframework.core.env.Environment; import org.springframework.jmx.export.MBeanExporter; import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; import org.springframework.jmx.export.annotation.AnnotationMBeanExporter; @@ -52,14 +52,15 @@ import org.springframework.util.StringUtils; * @since 1.0.0 */ @AutoConfiguration +@EnableConfigurationProperties(JmxProperties.class) @ConditionalOnClass({ MBeanExporter.class }) @ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true") public class JmxAutoConfiguration { - private final Environment environment; + private final JmxProperties properties; - public JmxAutoConfiguration(Environment environment) { - this.environment = environment; + public JmxAutoConfiguration(JmxProperties properties) { + this.properties = properties; } @Bean @@ -69,12 +70,11 @@ public class JmxAutoConfiguration { AnnotationMBeanExporter exporter = new AnnotationMBeanExporter(); exporter.setRegistrationPolicy(RegistrationPolicy.FAIL_ON_EXISTING); exporter.setNamingStrategy(namingStrategy); - String serverBean = this.environment.getProperty("spring.jmx.server", "mbeanServer"); + String serverBean = this.properties.getServer(); if (StringUtils.hasLength(serverBean)) { exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class)); } - boolean uniqueNames = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false); - exporter.setEnsureUniqueRuntimeObjectNames(uniqueNames); + exporter.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames()); return exporter; } @@ -82,12 +82,11 @@ public class JmxAutoConfiguration { @ConditionalOnMissingBean(value = ObjectNamingStrategy.class, search = SearchStrategy.CURRENT) public ParentAwareNamingStrategy objectNamingStrategy() { ParentAwareNamingStrategy namingStrategy = new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource()); - String defaultDomain = this.environment.getProperty("spring.jmx.default-domain"); + String defaultDomain = this.properties.getDefaultDomain(); if (StringUtils.hasLength(defaultDomain)) { namingStrategy.setDefaultDomain(defaultDomain); } - boolean uniqueNames = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false); - namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueNames); + namingStrategy.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames()); return namingStrategy; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxProperties.java new file mode 100644 index 0000000000..70466ee8dd --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxProperties.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2022 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.jmx; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for JMX. + * + * @author Scott Frederick + * @since 2.7.0 + */ +@ConfigurationProperties(prefix = "spring.jmx") +public class JmxProperties { + + /** + * Expose management beans to the JMX domain. + */ + private boolean enabled = false; + + /** + * Whether unique runtime object names should be ensured. + */ + private boolean uniqueNames = false; + + /** + * MBeanServer bean name. + */ + private String server = "mbeanServer"; + + /** + * JMX domain name. + */ + private String defaultDomain; + + public boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isUniqueNames() { + return this.uniqueNames; + } + + public void setUniqueNames(boolean uniqueNames) { + this.uniqueNames = uniqueNames; + } + + public String getServer() { + return this.server; + } + + public void setServer(String server) { + this.server = server; + } + + public String getDefaultDomain() { + return this.defaultDomain; + } + + public void setDefaultDomain(String defaultDomain) { + this.defaultDomain = defaultDomain; + } + +} 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 367b06ba72..b2cf23b9f7 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 @@ -1120,29 +1120,6 @@ "name": "spring.jersey.type", "defaultValue": "servlet" }, - { - "name": "spring.jmx.default-domain", - "type": "java.lang.String", - "description": "JMX domain name." - }, - { - "name": "spring.jmx.enabled", - "type": "java.lang.Boolean", - "description": "Expose management beans to the JMX domain.", - "defaultValue": false - }, - { - "name": "spring.jmx.server", - "type": "java.lang.String", - "description": "MBeanServer bean name.", - "defaultValue": "mbeanServer" - }, - { - "name": "spring.jmx.unique-names", - "type": "java.lang.Boolean", - "description": "Whether unique runtime object names should be ensured.", - "defaultValue": false - }, { "name": "spring.jpa.open-in-view", "defaultValue": true