Rework EndpointMBeanExporter to prevent name clashes and to provide more flexibility in naming of endpoint MBeans
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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<String, Object> properties = new HashMap<String, Object>();
|
||||
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<String, Object> properties = new HashMap<String, Object>();
|
||||
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<String> {
|
||||
|
||||
Reference in New Issue
Block a user