Merge pull request #13990 from ayudovin:support-ensureUniqueRuntimeObjectNames-globally
* pr/13990: Polish "Add global support for JMX unique names" Add global support for JMX unique names
This commit is contained in:
commit
e4e8311a1a
|
@ -22,6 +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.jmx.support.ObjectNameManager;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -40,11 +41,30 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
|
|||
|
||||
private final String contextId;
|
||||
|
||||
private final boolean uniqueNames;
|
||||
|
||||
DefaultEndpointObjectNameFactory(JmxEndpointProperties properties,
|
||||
MBeanServer mBeanServer, String contextId) {
|
||||
Environment environment, MBeanServer mBeanServer, String contextId) {
|
||||
this.properties = properties;
|
||||
this.mBeanServer = mBeanServer;
|
||||
this.contextId = contextId;
|
||||
this.uniqueNames = determineUniqueNames(environment, properties);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static boolean determineUniqueNames(Environment environment,
|
||||
JmxEndpointProperties properties) {
|
||||
Boolean uniqueName = environment.getProperty("spring.jmx.unique-names",
|
||||
Boolean.class);
|
||||
Boolean endpointUniqueNames = properties.getUniqueNames();
|
||||
if (uniqueName == null) {
|
||||
return (endpointUniqueNames != null) ? endpointUniqueNames : false;
|
||||
}
|
||||
else if (endpointUniqueNames != null & !uniqueName.equals(endpointUniqueNames)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration mismatch, 'management.endpoints.jmx.unique-names' is deprecated, use only 'spring.jmx.unique-names'");
|
||||
}
|
||||
return uniqueName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +77,7 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
|
|||
if (this.mBeanServer != null && hasMBean(baseName)) {
|
||||
builder.append(",context=" + this.contextId);
|
||||
}
|
||||
if (this.properties.isUniqueNames()) {
|
||||
if (this.uniqueNames) {
|
||||
String identity = ObjectUtils.getIdentityHexString(endpoint);
|
||||
builder.append(",identity=" + identity);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
|||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
|
@ -84,11 +85,11 @@ public class JmxEndpointAutoConfiguration {
|
|||
@Bean
|
||||
@ConditionalOnSingleCandidate(MBeanServer.class)
|
||||
public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer,
|
||||
ObjectProvider<ObjectMapper> objectMapper,
|
||||
Environment environment, ObjectProvider<ObjectMapper> objectMapper,
|
||||
JmxEndpointsSupplier jmxEndpointsSupplier) {
|
||||
String contextId = ObjectUtils.getIdentityHexString(this.applicationContext);
|
||||
EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory(
|
||||
this.properties, mBeanServer, contextId);
|
||||
this.properties, environment, mBeanServer, contextId);
|
||||
JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(
|
||||
objectMapper.getIfAvailable());
|
||||
return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper,
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Properties;
|
|||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
@ -41,9 +42,9 @@ public class JmxEndpointProperties {
|
|||
private String domain = "org.springframework.boot";
|
||||
|
||||
/**
|
||||
* Whether to ensure that ObjectNames are modified in case of conflict.
|
||||
* Whether unique runtime object names should be ensured.
|
||||
*/
|
||||
private boolean uniqueNames = false;
|
||||
private Boolean uniqueNames;
|
||||
|
||||
/**
|
||||
* Additional static properties to append to all ObjectNames of MBeans representing
|
||||
|
@ -70,11 +71,14 @@ public class JmxEndpointProperties {
|
|||
this.domain = domain;
|
||||
}
|
||||
|
||||
public boolean isUniqueNames() {
|
||||
@Deprecated
|
||||
@DeprecatedConfigurationProperty(replacement = "spring.jmx.unique-names")
|
||||
public Boolean getUniqueNames() {
|
||||
return this.uniqueNames;
|
||||
}
|
||||
|
||||
public void setUniqueNames(boolean uniqueNames) {
|
||||
@Deprecated
|
||||
public void setUniqueNames(Boolean uniqueNames) {
|
||||
this.uniqueNames = uniqueNames;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ import javax.management.MBeanServer;
|
|||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
@ -39,6 +41,9 @@ import static org.mockito.Mockito.mock;
|
|||
*/
|
||||
public class DefaultEndpointObjectNameFactoryTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final MockEnvironment environment = new MockEnvironment();
|
||||
|
||||
private final JmxEndpointProperties properties = new JmxEndpointProperties(
|
||||
|
@ -72,7 +77,18 @@ public class DefaultEndpointObjectNameFactoryTests {
|
|||
|
||||
@Test
|
||||
public void generateObjectNameWithUniqueNames() {
|
||||
this.environment.setProperty("spring.jmx.unique-names", "true");
|
||||
assertUniqueObjectName();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated
|
||||
public void generateObjectNameWithUniqueNamesDeprecatedProperty() {
|
||||
this.properties.setUniqueNames(true);
|
||||
assertUniqueObjectName();
|
||||
}
|
||||
|
||||
private void assertUniqueObjectName() {
|
||||
ExposableJmxEndpoint endpoint = endpoint("test");
|
||||
String id = ObjectUtils.getIdentityHexString(endpoint);
|
||||
ObjectName objectName = generateObjectName(endpoint);
|
||||
|
@ -80,6 +96,18 @@ public class DefaultEndpointObjectNameFactoryTests {
|
|||
"org.springframework.boot:type=Endpoint,name=Test,identity=" + id);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated
|
||||
public void generateObjectNameWithUniqueNamesDeprecatedPropertyMismatchMainProperty() {
|
||||
this.environment.setProperty("spring.jmx.unique-names", "false");
|
||||
this.properties.setUniqueNames(true);
|
||||
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("spring.jmx.unique-names");
|
||||
this.thrown.expectMessage("management.endpoints.jmx.unique-names");
|
||||
generateObjectName(endpoint("test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateObjectNameWithStaticNames() {
|
||||
this.properties.getStaticNames().setProperty("counter", "42");
|
||||
|
@ -107,8 +135,8 @@ public class DefaultEndpointObjectNameFactoryTests {
|
|||
|
||||
private ObjectName generateObjectName(ExposableJmxEndpoint endpoint) {
|
||||
try {
|
||||
return new DefaultEndpointObjectNameFactory(this.properties, this.mBeanServer,
|
||||
this.contextId).getObjectName(endpoint);
|
||||
return new DefaultEndpointObjectNameFactory(this.properties, this.environment,
|
||||
this.mBeanServer, this.contextId).getObjectName(endpoint);
|
||||
}
|
||||
catch (MalformedObjectNameException ex) {
|
||||
throw new AssertionError("Invalid object name", ex);
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Madhura Bhave
|
||||
* @author Artsiom Yudovin
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ MBeanExporter.class })
|
||||
|
@ -93,6 +94,9 @@ public class JmxAutoConfiguration implements EnvironmentAware, BeanFactoryAware
|
|||
if (StringUtils.hasLength(defaultDomain)) {
|
||||
namingStrategy.setDefaultDomain(defaultDomain);
|
||||
}
|
||||
boolean uniqueName = this.environment.getProperty("spring.jmx.unique-names",
|
||||
Boolean.class, false);
|
||||
namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueName);
|
||||
return namingStrategy;
|
||||
}
|
||||
|
||||
|
|
|
@ -290,6 +290,12 @@
|
|||
"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
|
||||
|
|
|
@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Tests for {@link JmxAutoConfiguration}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Artsiom Yudovin
|
||||
*/
|
||||
public class JmxAutoConfigurationTests {
|
||||
|
||||
|
@ -92,6 +93,7 @@ public class JmxAutoConfigurationTests {
|
|||
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);
|
||||
|
@ -102,6 +104,8 @@ public class JmxAutoConfigurationTests {
|
|||
.getField(mBeanExporter, "namingStrategy");
|
||||
assertThat(ReflectionTestUtils.getField(naming, "defaultDomain"))
|
||||
.isEqualTo("my-test-domain");
|
||||
assertThat(ReflectionTestUtils.getField(naming, "ensureUniqueRuntimeObjectNames"))
|
||||
.isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -100,6 +100,7 @@ content into your application. Rather, pick only the properties that you need.
|
|||
spring.jmx.default-domain= # JMX domain name.
|
||||
spring.jmx.enabled=true # Expose management beans to the JMX domain.
|
||||
spring.jmx.server=mbeanServer # MBeanServer bean name.
|
||||
spring.jmx.unique-names=false # Whether unique runtime object names should be ensured.
|
||||
|
||||
# Email ({sc-spring-boot-autoconfigure}/mail/MailProperties.{sc-ext}[MailProperties])
|
||||
spring.mail.default-encoding=UTF-8 # Default MimeMessage encoding.
|
||||
|
@ -1213,7 +1214,6 @@ content into your application. Rather, pick only the properties that you need.
|
|||
management.endpoints.jmx.exposure.include=* # Endpoint IDs that should be included or '*' for all.
|
||||
management.endpoints.jmx.exposure.exclude= # Endpoint IDs that should be excluded or '*' for all.
|
||||
management.endpoints.jmx.static-names= # Additional static properties to append to all ObjectNames of MBeans representing Endpoints.
|
||||
management.endpoints.jmx.unique-names=false # Whether to ensure that ObjectNames are modified in case of conflict.
|
||||
|
||||
# ENDPOINTS WEB CONFIGURATION ({sc-spring-boot-actuator-autoconfigure}/endpoint/web/WebEndpointProperties.{sc-ext}[WebEndpointProperties])
|
||||
management.endpoints.web.exposure.include=health,info # Endpoint IDs that should be included or '*' for all.
|
||||
|
|
|
@ -1200,17 +1200,16 @@ The name of the MBean is usually generated from the `id` of the endpoint. For ex
|
|||
`health` endpoint is exposed as `org.springframework.boot:type=Endpoint,name=Health`.
|
||||
|
||||
If your application contains more than one Spring `ApplicationContext`, you may find that
|
||||
names clash. To solve this problem, you can set the
|
||||
`management.endpoints.jmx.unique-names` property to `true` so that MBean names are always
|
||||
unique.
|
||||
names clash. To solve this problem, you can set the `spring.jmx.unique-names` property to
|
||||
`true` so that MBean names are always unique.
|
||||
|
||||
You can also customize the JMX domain under which endpoints are exposed. The following
|
||||
settings show an example of doing so in `application.properties`:
|
||||
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
spring.jmx.unique-names=true
|
||||
management.endpoints.jmx.domain=com.example.myapp
|
||||
management.endpoints.jmx.unique-names=true
|
||||
----
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue