Change naming strategy for endpoint mbeans
This commit is contained in:
parent
e2c962ac28
commit
31f7807acf
|
|
@ -16,19 +16,15 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
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.core.env.Environment;
|
||||
import org.springframework.jmx.export.MBeanExporter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for
|
||||
|
|
@ -42,20 +38,8 @@ import org.springframework.util.StringUtils;
|
|||
@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() {
|
||||
EndpointMBeanExporter mbeanExporter = new EndpointMBeanExporter();
|
||||
String domainName = this.environment.getProperty("endpoints.jmx.domain_name");
|
||||
if (StringUtils.hasText(domainName)) {
|
||||
mbeanExporter.setDomainName(domainName);
|
||||
}
|
||||
return mbeanExporter;
|
||||
return new EndpointMBeanExporter();
|
||||
}
|
||||
}
|
||||
|
|
@ -19,10 +19,16 @@ 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.ManagedOperation;
|
||||
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;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
|
@ -33,14 +39,24 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
* @author Christian Dupuis
|
||||
*/
|
||||
@ManagedResource
|
||||
public class EndpointMBean {
|
||||
public class EndpointMBean implements SelfNaming {
|
||||
|
||||
private AnnotationJmxAttributeSource annotationSource = new AnnotationJmxAttributeSource();
|
||||
|
||||
private MetadataNamingStrategy metadataNamingStrategy = new MetadataNamingStrategy(
|
||||
this.annotationSource);
|
||||
|
||||
private Endpoint<?> endpoint;
|
||||
|
||||
private String beanName;
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public EndpointMBean(Endpoint<?> endpoint) {
|
||||
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")
|
||||
|
|
@ -53,7 +69,7 @@ public class EndpointMBean {
|
|||
return this.endpoint.isSensitive();
|
||||
}
|
||||
|
||||
@ManagedOperation(description = "Invoke the underlying endpoint")
|
||||
@ManagedAttribute(description = "Invoke the underlying endpoint")
|
||||
public Object invoke() {
|
||||
Object result = this.endpoint.invoke();
|
||||
if (result == null) {
|
||||
|
|
@ -70,4 +86,9 @@ public class EndpointMBean {
|
|||
|
||||
return this.mapper.convertValue(result, Map.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName getObjectName() throws MalformedObjectNameException {
|
||||
return this.metadataNamingStrategy.getObjectName(this, this.beanName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,11 @@
|
|||
package org.springframework.boot.actuate.endpoint.jmx;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
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;
|
||||
|
|
@ -37,10 +34,7 @@ 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.jmx.support.JmxUtils;
|
||||
import org.springframework.jmx.support.ObjectNameManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link ApplicationListener} that registers all known {@link Endpoint}s with an
|
||||
|
|
@ -51,13 +45,8 @@ import org.springframework.util.ClassUtils;
|
|||
*/
|
||||
public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContextAware {
|
||||
|
||||
private static final String DEFAULT_DOMAIN_NAME = ClassUtils
|
||||
.getPackageName(Endpoint.class);
|
||||
|
||||
private static Log logger = LogFactory.getLog(EndpointMBeanExporter.class);
|
||||
|
||||
private String domainName = DEFAULT_DOMAIN_NAME;
|
||||
|
||||
private Set<Endpoint<?>> registeredEndpoints = new HashSet<Endpoint<?>>();
|
||||
|
||||
private volatile boolean autoStartup = true;
|
||||
|
|
@ -76,11 +65,6 @@ public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContext
|
|||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public void setDomainName(String domainName) {
|
||||
Assert.notNull(domainName, "DomainName must not be null");
|
||||
this.domainName = domainName;
|
||||
}
|
||||
|
||||
protected void doStart() {
|
||||
try {
|
||||
MBeanExporter mbeanExporter = this.applicationContext
|
||||
|
|
@ -108,29 +92,14 @@ public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContext
|
|||
}
|
||||
}
|
||||
|
||||
protected void registerEndpoint(String beanKey, Endpoint<?> endpoint,
|
||||
protected void registerEndpoint(String beanName, Endpoint<?> endpoint,
|
||||
MBeanExporter mbeanExporter) {
|
||||
try {
|
||||
mbeanExporter.registerManagedResource(new EndpointMBean(endpoint),
|
||||
getObjectName(beanKey, endpoint));
|
||||
mbeanExporter.registerManagedResource(new EndpointMBean(beanName, endpoint));
|
||||
}
|
||||
catch (MBeanExportException ex) {
|
||||
logger.error("Could not register MBean for endpoint [" + beanKey + "]", ex);
|
||||
logger.error("Could not register MBean for endpoint [" + beanName + "]", ex);
|
||||
}
|
||||
catch (MalformedObjectNameException ex) {
|
||||
logger.error("Could not register MBean for endpoint [" + beanKey + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected ObjectName getObjectName(String beanKey, Endpoint<?> endpoint)
|
||||
throws MalformedObjectNameException {
|
||||
// We have to be super careful to not create name clashes as multiple Boot
|
||||
// applications can potentially run in the same VM or MBeanServer. Therefore
|
||||
// append the object identity to the ObjectName.
|
||||
Hashtable<String, String> properties = new Hashtable<String, String>();
|
||||
properties.put("bean", beanKey);
|
||||
return JmxUtils.appendIdentityToObjectName(
|
||||
ObjectNameManager.getInstance(this.domainName, properties), endpoint);
|
||||
}
|
||||
|
||||
// SmartLifeCycle implementation
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
package org.springframework.boot.actuate.endpoint.jmx;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
|
@ -29,11 +27,10 @@ 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.JmxUtils;
|
||||
import org.springframework.jmx.support.ObjectNameManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
|
@ -61,8 +58,11 @@ public class EndpointMBeanExporterTests {
|
|||
new RootBeanDefinition(EndpointMBeanExporter.class));
|
||||
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||
TestEndpoint.class));
|
||||
this.context.registerBeanDefinition("mbeanExporter", new RootBeanDefinition(
|
||||
MBeanExporter.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);
|
||||
|
|
@ -70,8 +70,8 @@ public class EndpointMBeanExporterTests {
|
|||
MBeanInfo mbeanInfo = mbeanExporter.getServer().getMBeanInfo(
|
||||
getObjectName("endpoint1", this.context));
|
||||
assertNotNull(mbeanInfo);
|
||||
assertEquals(3, mbeanInfo.getOperations().length);
|
||||
assertEquals(2, mbeanInfo.getAttributes().length);
|
||||
assertEquals(4, mbeanInfo.getOperations().length);
|
||||
assertEquals(3, mbeanInfo.getAttributes().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -83,8 +83,11 @@ public class EndpointMBeanExporterTests {
|
|||
TestEndpoint.class));
|
||||
this.context.registerBeanDefinition("endpoint2", new RootBeanDefinition(
|
||||
TestEndpoint.class));
|
||||
this.context.registerBeanDefinition("mbeanExporter", new RootBeanDefinition(
|
||||
MBeanExporter.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);
|
||||
|
|
@ -102,66 +105,30 @@ public class EndpointMBeanExporterTests {
|
|||
new RootBeanDefinition(EndpointMBeanExporter.class));
|
||||
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||
TestEndpoint.class));
|
||||
this.context.registerBeanDefinition("mbeanExporter", new RootBeanDefinition(
|
||||
MBeanExporter.class));
|
||||
this.context.registerBeanDefinition(
|
||||
"mbeanExporter",
|
||||
new RootBeanDefinition(MBeanExporter.class, null,
|
||||
new MutablePropertyValues(Collections.singletonMap(
|
||||
"ensureUniqueRuntimeObjectNames", "false"))));
|
||||
|
||||
GenericApplicationContext parent = new GenericApplicationContext();
|
||||
parent.registerBeanDefinition("endpointMbeanExporter", new RootBeanDefinition(
|
||||
EndpointMBeanExporter.class));
|
||||
parent.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||
TestEndpoint.class));
|
||||
parent.registerBeanDefinition("mbeanExporter", new RootBeanDefinition(
|
||||
MBeanExporter.class));
|
||||
|
||||
this.context.setParent(parent);
|
||||
parent.refresh();
|
||||
this.context.refresh();
|
||||
|
||||
MBeanExporter mbeanExporter = parent.getBean(MBeanExporter.class);
|
||||
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
|
||||
|
||||
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
||||
getObjectName("endpoint1", this.context)));
|
||||
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
||||
getObjectName("endpoint1", parent)));
|
||||
|
||||
parent.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrationWithCustomDomainAndKey() throws Exception {
|
||||
Map<String, String> propertyValues = new HashMap<String, String>();
|
||||
propertyValues.put("domainName", "test.domain");
|
||||
|
||||
this.context = new GenericApplicationContext();
|
||||
this.context.registerBeanDefinition("endpointMbeanExporter",
|
||||
new RootBeanDefinition(EndpointMBeanExporter.class, null,
|
||||
new MutablePropertyValues(propertyValues)));
|
||||
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||
TestEndpoint.class));
|
||||
this.context.registerBeanDefinition("mbeanExporter", new RootBeanDefinition(
|
||||
MBeanExporter.class));
|
||||
this.context.refresh();
|
||||
|
||||
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
|
||||
|
||||
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
||||
getObjectName("test.domain", "endpoint1", this.context,
|
||||
this.context.getBean("endpoint1"))));
|
||||
}
|
||||
|
||||
private ObjectName getObjectName(String beanKey, ApplicationContext applicationContext)
|
||||
throws MalformedObjectNameException {
|
||||
return getObjectName("org.springframework.boot.actuate.endpoint", beanKey,
|
||||
applicationContext, applicationContext.getBean(beanKey));
|
||||
}
|
||||
|
||||
private ObjectName getObjectName(String domainName, String beanKey,
|
||||
ApplicationContext applicationContext, Object object)
|
||||
throws MalformedObjectNameException {
|
||||
Hashtable<String, String> properties = new Hashtable<String, String>();
|
||||
properties.put("bean", beanKey);
|
||||
return JmxUtils.appendIdentityToObjectName(
|
||||
ObjectNameManager.getInstance(domainName, properties), object);
|
||||
return new EndpointMBean(beanKey,
|
||||
(Endpoint<?>) applicationContext.getBean(beanKey)).getObjectName();
|
||||
}
|
||||
|
||||
public static class TestEndpoint extends AbstractEndpoint<String> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue