From 65d6757a10ad03e6e6704f6440342f79ea3945ae Mon Sep 17 00:00:00 2001 From: Christian Dupuis Date: Thu, 26 Dec 2013 15:07:42 +0100 Subject: [PATCH] Rework EndpointMBeanExporter to prevent name clashes and to provide more flexibility in naming of endpoint MBeans --- .../EndpointMBeanExportAutoConfiguration.java | 40 +++++- .../actuate/endpoint/jmx/EndpointMBean.java | 21 +-- .../endpoint/jmx/EndpointMBeanExporter.java | 132 ++++++++++++++---- ...ointMBeanExportAutoConfigurationTests.java | 43 ++++++ .../jmx/EndpointMBeanExporterTests.java | 116 +++++++++++---- 5 files changed, 274 insertions(+), 78 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfiguration.java index 4197ed153a..ff0bd8509b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfiguration.java @@ -16,15 +16,19 @@ package org.springframework.boot.actuate.autoconfigure; +import java.util.Properties; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.jmx.export.MBeanExporter; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for @@ -33,13 +37,41 @@ import org.springframework.jmx.export.MBeanExporter; * @author Christian Dupuis */ @Configuration -@ConditionalOnBean({ MBeanExporter.class }) @AutoConfigureAfter({ EndpointAutoConfiguration.class }) @ConditionalOnExpression("${endpoints.jmx.enabled:true}") class EndpointMBeanExportAutoConfiguration { + private RelaxedPropertyResolver environment; + + @Autowired + public void setEnvironment(Environment environment) { + this.environment = new RelaxedPropertyResolver(environment); + } + @Bean public EndpointMBeanExporter endpointMBeanExporter() { - return new EndpointMBeanExporter(); + EndpointMBeanExporter mbeanExporter = new EndpointMBeanExporter(); + + String domain = this.environment.getProperty("endpoints.jmx.domain"); + if (StringUtils.hasText(domain)) { + mbeanExporter.setDomain(domain); + } + + Boolean ensureUnique = this.environment.getProperty("endpoints.jmx.unique_names", + Boolean.class, Boolean.FALSE); + mbeanExporter.setEnsureUniqueRuntimeObjectNames(ensureUnique); + + mbeanExporter.setObjectNameStaticProperties(getObjectNameStaticProperties()); + + return mbeanExporter; + } + + private Properties getObjectNameStaticProperties() { + String staticNames = this.environment.getProperty("endpoints.jmx.static_names"); + if (StringUtils.hasText(staticNames)) { + return StringUtils.splitArrayElementsIntoProperties( + StringUtils.commaDelimitedListToStringArray(staticNames), "="); + } + return new Properties(); } } \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java index 85c1f0432f..086b5a883c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java @@ -19,15 +19,9 @@ package org.springframework.boot.actuate.endpoint.jmx; import java.util.List; import java.util.Map; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedResource; -import org.springframework.jmx.export.naming.MetadataNamingStrategy; -import org.springframework.jmx.export.naming.SelfNaming; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -39,24 +33,16 @@ import com.fasterxml.jackson.databind.ObjectMapper; * @author Christian Dupuis */ @ManagedResource -public class EndpointMBean implements SelfNaming { - - private AnnotationJmxAttributeSource annotationSource = new AnnotationJmxAttributeSource(); - - private MetadataNamingStrategy metadataNamingStrategy = new MetadataNamingStrategy( - this.annotationSource); +public class EndpointMBean { private Endpoint endpoint; - private String beanName; - private ObjectMapper mapper = new ObjectMapper(); public EndpointMBean(String beanName, Endpoint endpoint) { Assert.notNull(beanName, "BeanName must not be null"); Assert.notNull(endpoint, "Endpoint must not be null"); this.endpoint = endpoint; - this.beanName = beanName; } @ManagedAttribute(description = "Returns the class of the underlying endpoint") @@ -69,11 +55,6 @@ public class EndpointMBean implements SelfNaming { return this.endpoint.isSensitive(); } - @Override - public ObjectName getObjectName() throws MalformedObjectNameException { - return this.metadataNamingStrategy.getObjectName(this, this.beanName); - } - public Endpoint getEndpoint() { return this.endpoint; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java index 7f1592032d..7e4fa77918 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java @@ -18,24 +18,31 @@ package org.springframework.boot.actuate.endpoint.jmx; import java.util.HashSet; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; import org.springframework.context.SmartLifecycle; import org.springframework.jmx.export.MBeanExportException; import org.springframework.jmx.export.MBeanExporter; -import org.springframework.util.Assert; +import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; +import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler; +import org.springframework.jmx.export.naming.MetadataNamingStrategy; +import org.springframework.jmx.export.naming.SelfNaming; +import org.springframework.jmx.support.ObjectNameManager; +import org.springframework.util.ObjectUtils; /** * {@link ApplicationListener} that registers all known {@link Endpoint}s with an @@ -44,10 +51,21 @@ import org.springframework.util.Assert; * * @author Christian Dupuis */ -public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContextAware { +public class EndpointMBeanExporter extends MBeanExporter implements SmartLifecycle, + BeanFactoryAware { + + public static final String DEFAULT_DOMAIN = "org.springframework.boot"; private static Log logger = LogFactory.getLog(EndpointMBeanExporter.class); + private final AnnotationJmxAttributeSource attributeSource = new AnnotationJmxAttributeSource(); + + private final MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler( + this.attributeSource); + + private final MetadataNamingStrategy defaultNamingStrategy = new MetadataNamingStrategy( + this.attributeSource); + private Set> registeredEndpoints = new HashSet>(); private volatile boolean autoStartup = true; @@ -58,45 +76,65 @@ public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContext private final ReentrantLock lifecycleLock = new ReentrantLock(); - private ApplicationContext applicationContext; + private ListableBeanFactory beanFactory; - @Override - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; + private String domain = DEFAULT_DOMAIN; + + private boolean ensureUniqueRuntimeObjectNames = false; + + private Properties objectNameStaticProperties = new Properties(); + + public EndpointMBeanExporter() { + super(); + setAutodetect(false); + setNamingStrategy(this.defaultNamingStrategy); + setAssembler(this.assembler); } - protected void doStart() { - try { - MBeanExporter mbeanExporter = this.applicationContext - .getBean(MBeanExporter.class); - locateAndRegisterEndpoints(mbeanExporter); + @Override + public void setBeanFactory(BeanFactory beanFactory) { + super.setBeanFactory(beanFactory); + if (beanFactory instanceof ListableBeanFactory) { + this.beanFactory = (ListableBeanFactory) beanFactory; } - catch (NoSuchBeanDefinitionException nsbde) { - if (logger.isDebugEnabled()) { - logger.debug("Could not obtain MBeanExporter. No Endpoint JMX export will be attemted."); - } + else { + logger.info("EndpointMBeanExporter not running in a ListableBeanFactory: " + + "autodetection of Endpoints not available."); } } + public void setDomain(String domain) { + this.domain = domain; + } + + @Override + public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) { + super.setEnsureUniqueRuntimeObjectNames(ensureUniqueRuntimeObjectNames); + this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames; + } + + public void setObjectNameStaticProperties(Properties objectNameStaticProperties) { + this.objectNameStaticProperties = objectNameStaticProperties; + } + + protected void doStart() { + locateAndRegisterEndpoints(); + } + @SuppressWarnings({ "rawtypes" }) - protected void locateAndRegisterEndpoints(MBeanExporter mbeanExporter) { - Assert.notNull(mbeanExporter, "MBeanExporter must not be null"); - Map endpoints = this.applicationContext - .getBeansOfType(Endpoint.class); + protected void locateAndRegisterEndpoints() { + Map endpoints = this.beanFactory.getBeansOfType(Endpoint.class); for (Map.Entry endpointEntry : endpoints.entrySet()) { if (!this.registeredEndpoints.contains(endpointEntry.getValue())) { - registerEndpoint(endpointEntry.getKey(), endpointEntry.getValue(), - mbeanExporter); + registerEndpoint(endpointEntry.getKey(), endpointEntry.getValue()); this.registeredEndpoints.add(endpointEntry.getValue()); } } } - protected void registerEndpoint(String beanName, Endpoint endpoint, - MBeanExporter mbeanExporter) { + protected void registerEndpoint(String beanName, Endpoint endpoint) { try { - mbeanExporter.registerManagedResource(getEndpointMBean(beanName, endpoint)); + registerBeanNameOrInstance(getEndpointMBean(beanName, endpoint), beanName); } catch (MBeanExportException ex) { logger.error("Could not register MBean for endpoint [" + beanName + "]", ex); @@ -110,6 +148,42 @@ public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContext return new DataEndpointMBean(beanName, endpoint); } + @Override + protected ObjectName getObjectName(Object bean, String beanKey) + throws MalformedObjectNameException { + if (bean instanceof SelfNaming) { + return ((SelfNaming) bean).getObjectName(); + } + + if (bean instanceof EndpointMBean) { + StringBuilder builder = new StringBuilder(); + builder.append(this.domain); + builder.append(":type=Endpoint"); + builder.append(",name=" + beanKey); + if (this.ensureUniqueRuntimeObjectNames) { + builder.append(",identity=" + + ObjectUtils.getIdentityHexString(((EndpointMBean) bean) + .getEndpoint())); + } + builder.append(getStaticNames()); + return ObjectNameManager.getInstance(builder.toString()); + } + + return this.defaultNamingStrategy.getObjectName(bean, beanKey); + } + + private String getStaticNames() { + if (this.objectNameStaticProperties.isEmpty()) { + return ""; + } + StringBuilder builder = new StringBuilder(); + + for (Object key : this.objectNameStaticProperties.keySet()) { + builder.append("," + key + "=" + this.objectNameStaticProperties.get(key)); + } + return builder.toString(); + } + // SmartLifeCycle implementation public final int getPhase() { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java index 7f83e19c10..c8c65240b3 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointMBeanExportAutoConfigurationTests.java @@ -16,13 +16,24 @@ package org.springframework.boot.actuate.autoconfigure; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; + import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableMBeanExport; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.support.ObjectNameManager; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ObjectUtils; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -53,7 +64,10 @@ public class EndpointMBeanExportAutoConfigurationTests { @Test(expected = NoSuchBeanDefinitionException.class) public void testEndpointMBeanExporterIsNotInstalled() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("endpoints.jmx.enabled", "false"); this.context = new AnnotationConfigApplicationContext(); + this.context.setEnvironment(environment); this.context.register(EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); this.context.refresh(); @@ -61,6 +75,35 @@ public class EndpointMBeanExportAutoConfigurationTests { fail(); } + @Test + public void testEndpointMBeanExporterWithProperties() throws IntrospectionException, + InstanceNotFoundException, MalformedObjectNameException, ReflectionException { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("endpoints.jmx.domain", "test-domain"); + environment.setProperty("endpoints.jmx.unique_names", "true"); + environment.setProperty("endpoints.jmx.static_names", "key1=value1, key2=value2"); + this.context = new AnnotationConfigApplicationContext(); + this.context.setEnvironment(environment); + this.context.register(EndpointAutoConfiguration.class, + EndpointMBeanExportAutoConfiguration.class); + this.context.refresh(); + this.context.getBean(EndpointMBeanExporter.class); + + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); + + assertNotNull(mbeanExporter.getServer().getMBeanInfo( + ObjectNameManager.getInstance(getObjectName("test-domain", + "healthEndpoint", this.context).toString() + + ",key1=value1,key2=value2"))); + } + + private ObjectName getObjectName(String domain, String beanKey, + ApplicationContext applicationContext) throws MalformedObjectNameException { + return ObjectNameManager.getInstance(String.format( + "%s:type=Endpoint,name=%s,identity=%s", domain, beanKey, + ObjectUtils.getIdentityHexString(applicationContext.getBean(beanKey)))); + } + @Configuration @EnableMBeanExport public static class TestConfiguration { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java index b0b041113c..5022c0bf30 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java @@ -17,6 +17,9 @@ package org.springframework.boot.actuate.endpoint.jmx; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; import javax.management.MBeanInfo; import javax.management.MalformedObjectNameException; @@ -27,10 +30,11 @@ import org.junit.Test; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.support.ObjectNameManager; +import org.springframework.util.ObjectUtils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -58,20 +62,15 @@ public class EndpointMBeanExporterTests { new RootBeanDefinition(EndpointMBeanExporter.class)); this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition( TestEndpoint.class)); - this.context.registerBeanDefinition( - "mbeanExporter", - new RootBeanDefinition(MBeanExporter.class, null, - new MutablePropertyValues(Collections.singletonMap( - "ensureUniqueRuntimeObjectNames", "false")))); this.context.refresh(); - MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class); + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); MBeanInfo mbeanInfo = mbeanExporter.getServer().getMBeanInfo( getObjectName("endpoint1", this.context)); assertNotNull(mbeanInfo); - assertEquals(5, mbeanInfo.getOperations().length); - assertEquals(5, mbeanInfo.getAttributes().length); + assertEquals(3, mbeanInfo.getOperations().length); + assertEquals(3, mbeanInfo.getAttributes().length); } @Test @@ -83,14 +82,9 @@ public class EndpointMBeanExporterTests { TestEndpoint.class)); this.context.registerBeanDefinition("endpoint2", new RootBeanDefinition( TestEndpoint.class)); - this.context.registerBeanDefinition( - "mbeanExporter", - new RootBeanDefinition(MBeanExporter.class, null, - new MutablePropertyValues(Collections.singletonMap( - "ensureUniqueRuntimeObjectNames", "false")))); this.context.refresh(); - MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class); + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertNotNull(mbeanExporter.getServer().getMBeanInfo( getObjectName("endpoint1", this.context))); @@ -98,6 +92,69 @@ public class EndpointMBeanExporterTests { getObjectName("endpoint2", this.context))); } + @Test + public void testRegistrationWithDifferentDomain() throws Exception { + this.context = new GenericApplicationContext(); + this.context.registerBeanDefinition( + "endpointMbeanExporter", + new RootBeanDefinition(EndpointMBeanExporter.class, null, + new MutablePropertyValues(Collections.singletonMap("domain", + "test-domain")))); + this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition( + TestEndpoint.class)); + this.context.refresh(); + + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); + + assertNotNull(mbeanExporter.getServer().getMBeanInfo( + getObjectName("test-domain", "endpoint1", false, this.context))); + } + + @Test + public void testRegistrationWithDifferentDomainAndIdentity() throws Exception { + Map properties = new HashMap(); + properties.put("domain", "test-domain"); + properties.put("ensureUniqueRuntimeObjectNames", true); + this.context = new GenericApplicationContext(); + this.context.registerBeanDefinition("endpointMbeanExporter", + new RootBeanDefinition(EndpointMBeanExporter.class, null, + new MutablePropertyValues(properties))); + this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition( + TestEndpoint.class)); + this.context.refresh(); + + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); + + assertNotNull(mbeanExporter.getServer().getMBeanInfo( + getObjectName("test-domain", "endpoint1", true, this.context))); + } + + @Test + public void testRegistrationWithDifferentDomainAndIdentityAndStaticNames() + throws Exception { + Map properties = new HashMap(); + properties.put("domain", "test-domain"); + properties.put("ensureUniqueRuntimeObjectNames", true); + Properties staticNames = new Properties(); + staticNames.put("key1", "value1"); + staticNames.put("key2", "value2"); + properties.put("objectNameStaticProperties", staticNames); + this.context = new GenericApplicationContext(); + this.context.registerBeanDefinition("endpointMbeanExporter", + new RootBeanDefinition(EndpointMBeanExporter.class, null, + new MutablePropertyValues(properties))); + this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition( + TestEndpoint.class)); + this.context.refresh(); + + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); + + assertNotNull(mbeanExporter.getServer().getMBeanInfo( + ObjectNameManager.getInstance(getObjectName("test-domain", "endpoint1", + true, this.context).toString() + + ",key1=value1,key2=value2"))); + } + @Test public void testRegistrationWithParentContext() throws Exception { this.context = new GenericApplicationContext(); @@ -105,19 +162,13 @@ public class EndpointMBeanExporterTests { new RootBeanDefinition(EndpointMBeanExporter.class)); this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition( TestEndpoint.class)); - this.context.registerBeanDefinition( - "mbeanExporter", - new RootBeanDefinition(MBeanExporter.class, null, - new MutablePropertyValues(Collections.singletonMap( - "ensureUniqueRuntimeObjectNames", "false")))); - GenericApplicationContext parent = new GenericApplicationContext(); this.context.setParent(parent); parent.refresh(); this.context.refresh(); - MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class); + MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertNotNull(mbeanExporter.getServer().getMBeanInfo( getObjectName("endpoint1", this.context))); @@ -125,10 +176,25 @@ public class EndpointMBeanExporterTests { parent.close(); } - private ObjectName getObjectName(String beanKey, ApplicationContext applicationContext) + private ObjectName getObjectName(String beanKey, GenericApplicationContext context) throws MalformedObjectNameException { - return new DataEndpointMBean(beanKey, - (Endpoint) applicationContext.getBean(beanKey)).getObjectName(); + return getObjectName("org.springframework.boot", beanKey, false, context); + } + + private ObjectName getObjectName(String domain, String beanKey, + boolean includeIdentity, ApplicationContext applicationContext) + throws MalformedObjectNameException { + if (includeIdentity) { + return ObjectNameManager + .getInstance(String.format("%s:type=Endpoint,name=%s,identity=%s", + domain, beanKey, ObjectUtils + .getIdentityHexString(applicationContext + .getBean(beanKey)))); + } + else { + return ObjectNameManager.getInstance(String.format( + "%s:type=Endpoint,name=%s", domain, beanKey)); + } } public static class TestEndpoint extends AbstractEndpoint {