Polish "Add global support for JMX unique names"
This commit ensures that the new "spring.jmx.unique-names" property deprecates the Endpoint's specific property as they share the same goal. If both are set with an incompatible value, an exception is thrown inviting the user to update their configuration. Closes gh-13990
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -94,11 +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;
|
||||
}
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
{
|
||||
"name": "spring.jmx.unique-names",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to ensure that ObjectNames are modified in case of conflict.",
|
||||
"description": "Whether unique runtime object names should be ensured.",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -100,7 +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 # Set if unique runtime object names should be ensured.
|
||||
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.
|
||||
@@ -1214,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
|
||||
----
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user