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
pull/30406/head
Scott Frederick 3 years ago
parent 704a2b7795
commit e5a09b3b31

@ -48,6 +48,7 @@ import org.springframework.util.StringUtils;
* @author Christian Dupuis * @author Christian Dupuis
* @author Madhura Bhave * @author Madhura Bhave
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Scott Frederick
* @since 1.0.0 * @since 1.0.0
*/ */
@AutoConfiguration @AutoConfiguration
@ -72,6 +73,8 @@ public class JmxAutoConfiguration {
if (StringUtils.hasLength(serverBean)) { if (StringUtils.hasLength(serverBean)) {
exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class)); exporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class));
} }
boolean uniqueNames = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false);
exporter.setEnsureUniqueRuntimeObjectNames(uniqueNames);
return exporter; return exporter;
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,12 +16,12 @@
package org.springframework.boot.autoconfigure.jmx; package org.springframework.boot.autoconfigure.jmx;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; 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.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.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.naming.MetadataNamingStrategy; 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 org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/** /**
* Tests for {@link JmxAutoConfiguration}. * Tests for {@link JmxAutoConfiguration}.
* *
* @author Christian Dupuis * @author Christian Dupuis
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Scott Frederick
*/ */
class JmxAutoConfigurationTests { class JmxAutoConfigurationTests {
private AnnotationConfigApplicationContext context; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class));
@AfterEach
void tearDown() {
if (this.context != null) {
this.context.close();
if (this.context.getParent() != null) {
((ConfigurableApplicationContext) this.context.getParent()).close();
}
}
}
@Test @Test
void testDefaultMBeanExport() { void testDefaultMBeanExport() {
this.context = new AnnotationConfigApplicationContext(); this.contextRunner.run((context) -> {
this.context.register(JmxAutoConfiguration.class); assertThat(context).doesNotHaveBean(MBeanExporter.class);
this.context.refresh(); assertThat(context).doesNotHaveBean(ObjectNamingStrategy.class);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class) });
.isThrownBy(() -> this.context.getBean(MBeanExporter.class));
} }
@Test @Test
void testEnabledMBeanExport() { void testDisabledMBeanExport() {
MockEnvironment env = new MockEnvironment(); this.contextRunner.withPropertyValues("spring.jmx.enabled=false").run((context) -> {
env.setProperty("spring.jmx.enabled", "true"); assertThat(context).doesNotHaveBean(MBeanExporter.class);
this.context = new AnnotationConfigApplicationContext(); assertThat(context).doesNotHaveBean(ObjectNamingStrategy.class);
this.context.setEnvironment(env); });
this.context.register(JmxAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBean(MBeanExporter.class)).isNotNull();
} }
@Test @Test
void testDisabledMBeanExport() { void testEnabledMBeanExport() {
MockEnvironment env = new MockEnvironment(); this.contextRunner.withPropertyValues("spring.jmx.enabled=true").run((context) -> {
env.setProperty("spring.jmx.enabled", "false"); assertThat(context).hasSingleBean(MBeanExporter.class);
this.context = new AnnotationConfigApplicationContext(); assertThat(context).hasSingleBean(ParentAwareNamingStrategy.class);
this.context.setEnvironment(env); MBeanExporter exporter = context.getBean(MBeanExporter.class);
this.context.register(TestConfiguration.class, JmxAutoConfiguration.class); assertThat(exporter).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", false);
this.context.refresh(); MetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter,
assertThatExceptionOfType(NoSuchBeanDefinitionException.class) "namingStrategy");
.isThrownBy(() -> this.context.getBean(MBeanExporter.class)); assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", false);
});
} }
@Test @Test
void testDefaultDomainConfiguredOnMBeanExport() { void testDefaultDomainConfiguredOnMBeanExport() {
MockEnvironment env = new MockEnvironment(); this.contextRunner.withPropertyValues("spring.jmx.enabled=true", "spring.jmx.default-domain=my-test-domain",
env.setProperty("spring.jmx.enabled", "true"); "spring.jmx.unique-names=true").run((context) -> {
env.setProperty("spring.jmx.default-domain", "my-test-domain"); assertThat(context).hasSingleBean(MBeanExporter.class);
env.setProperty("spring.jmx.unique-names", "true"); MBeanExporter exporter = context.getBean(MBeanExporter.class);
this.context = new AnnotationConfigApplicationContext(); assertThat(exporter).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true);
this.context.setEnvironment(env); MetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter,
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"); "namingStrategy");
assertThat(naming).hasFieldOrPropertyWithValue("defaultDomain", "my-test-domain"); assertThat(naming).hasFieldOrPropertyWithValue("defaultDomain", "my-test-domain");
assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true); assertThat(naming).hasFieldOrPropertyWithValue("ensureUniqueRuntimeObjectNames", true);
});
} }
@Test @Test
void testBasicParentContext() { void testBasicParentContext() {
this.context = new AnnotationConfigApplicationContext(); try (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) {
this.context.register(JmxAutoConfiguration.class); parent.register(JmxAutoConfiguration.class);
this.context.refresh(); parent.refresh();
AnnotationConfigApplicationContext parent = this.context; this.contextRunner.withParent(parent).run((context) -> assertThat(context.isRunning()));
this.context = new AnnotationConfigApplicationContext(); }
this.context.setParent(parent);
this.context.register(JmxAutoConfiguration.class);
this.context.refresh();
} }
@Test @Test
void testParentContext() { void testParentContext() {
this.context = new AnnotationConfigApplicationContext(); try (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) {
this.context.register(JmxAutoConfiguration.class, TestConfiguration.class); parent.register(JmxAutoConfiguration.class, TestConfiguration.class);
this.context.refresh(); parent.refresh();
AnnotationConfigApplicationContext parent = this.context; this.contextRunner.withParent(parent).withConfiguration(UserConfigurations.of(TestConfiguration.class))
this.context = new AnnotationConfigApplicationContext(); .run((context) -> assertThat(context.isRunning()));
this.context.setParent(parent); }
this.context.register(JmxAutoConfiguration.class, TestConfiguration.class);
this.context.refresh();
} }
@Test @Test
void customJmxDomain() { void customJmxDomain() {
this.context = new AnnotationConfigApplicationContext(); this.contextRunner.withConfiguration(UserConfigurations.of(CustomJmxDomainConfiguration.class))
this.context.register(CustomJmxDomainConfiguration.class, JmxAutoConfiguration.class, .withConfiguration(
IntegrationAutoConfiguration.class); AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class))
this.context.refresh(); .run((context) -> {
IntegrationMBeanExporter mbeanExporter = this.context.getBean(IntegrationMBeanExporter.class); assertThat(context).hasSingleBean(IntegrationMBeanExporter.class);
assertThat(mbeanExporter).hasFieldOrPropertyWithValue("domain", "foo.my"); IntegrationMBeanExporter exporter = context.getBean(IntegrationMBeanExporter.class);
assertThat(exporter).hasFieldOrPropertyWithValue("domain", "foo.my");
});
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)

Loading…
Cancel
Save