Rework EndpointMBeanExporter to prevent name clashes and to provide more flexibility in naming of endpoint MBeans
This commit is contained in:
parent
b81930fcce
commit
65d6757a10
|
|
@ -16,15 +16,19 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure;
|
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.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
|
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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
|
* {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for
|
||||||
|
|
@ -33,13 +37,41 @@ import org.springframework.jmx.export.MBeanExporter;
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnBean({ MBeanExporter.class })
|
|
||||||
@AutoConfigureAfter({ EndpointAutoConfiguration.class })
|
@AutoConfigureAfter({ EndpointAutoConfiguration.class })
|
||||||
@ConditionalOnExpression("${endpoints.jmx.enabled:true}")
|
@ConditionalOnExpression("${endpoints.jmx.enabled:true}")
|
||||||
class EndpointMBeanExportAutoConfiguration {
|
class EndpointMBeanExportAutoConfiguration {
|
||||||
|
|
||||||
|
private RelaxedPropertyResolver environment;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
this.environment = new RelaxedPropertyResolver(environment);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public EndpointMBeanExporter endpointMBeanExporter() {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,15 +19,9 @@ package org.springframework.boot.actuate.endpoint.jmx;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.management.MalformedObjectNameException;
|
|
||||||
import javax.management.ObjectName;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
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.ManagedAttribute;
|
||||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
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.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
|
@ -39,24 +33,16 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
*/
|
*/
|
||||||
@ManagedResource
|
@ManagedResource
|
||||||
public class EndpointMBean implements SelfNaming {
|
public class EndpointMBean {
|
||||||
|
|
||||||
private AnnotationJmxAttributeSource annotationSource = new AnnotationJmxAttributeSource();
|
|
||||||
|
|
||||||
private MetadataNamingStrategy metadataNamingStrategy = new MetadataNamingStrategy(
|
|
||||||
this.annotationSource);
|
|
||||||
|
|
||||||
private Endpoint<?> endpoint;
|
private Endpoint<?> endpoint;
|
||||||
|
|
||||||
private String beanName;
|
|
||||||
|
|
||||||
private ObjectMapper mapper = new ObjectMapper();
|
private ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
public EndpointMBean(String beanName, Endpoint<?> endpoint) {
|
public EndpointMBean(String beanName, Endpoint<?> endpoint) {
|
||||||
Assert.notNull(beanName, "BeanName must not be null");
|
Assert.notNull(beanName, "BeanName must not be null");
|
||||||
Assert.notNull(endpoint, "Endpoint must not be null");
|
Assert.notNull(endpoint, "Endpoint must not be null");
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
this.beanName = beanName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManagedAttribute(description = "Returns the class of the underlying endpoint")
|
@ManagedAttribute(description = "Returns the class of the underlying endpoint")
|
||||||
|
|
@ -69,11 +55,6 @@ public class EndpointMBean implements SelfNaming {
|
||||||
return this.endpoint.isSensitive();
|
return this.endpoint.isSensitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectName getObjectName() throws MalformedObjectNameException {
|
|
||||||
return this.metadataNamingStrategy.getObjectName(this, this.beanName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Endpoint<?> getEndpoint() {
|
public Endpoint<?> getEndpoint() {
|
||||||
return this.endpoint;
|
return this.endpoint;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,24 +18,31 @@ package org.springframework.boot.actuate.endpoint.jmx;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import javax.management.MBeanServer;
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.MalformedObjectNameException;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
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.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
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.ApplicationListener;
|
||||||
import org.springframework.context.SmartLifecycle;
|
import org.springframework.context.SmartLifecycle;
|
||||||
import org.springframework.jmx.export.MBeanExportException;
|
import org.springframework.jmx.export.MBeanExportException;
|
||||||
import org.springframework.jmx.export.MBeanExporter;
|
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
|
* {@link ApplicationListener} that registers all known {@link Endpoint}s with an
|
||||||
|
|
@ -44,10 +51,21 @@ import org.springframework.util.Assert;
|
||||||
*
|
*
|
||||||
* @author Christian Dupuis
|
* @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 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<Endpoint<?>> registeredEndpoints = new HashSet<Endpoint<?>>();
|
private Set<Endpoint<?>> registeredEndpoints = new HashSet<Endpoint<?>>();
|
||||||
|
|
||||||
private volatile boolean autoStartup = true;
|
private volatile boolean autoStartup = true;
|
||||||
|
|
@ -58,45 +76,65 @@ public class EndpointMBeanExporter implements SmartLifecycle, ApplicationContext
|
||||||
|
|
||||||
private final ReentrantLock lifecycleLock = new ReentrantLock();
|
private final ReentrantLock lifecycleLock = new ReentrantLock();
|
||||||
|
|
||||||
private ApplicationContext applicationContext;
|
private ListableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext applicationContext)
|
public void setBeanFactory(BeanFactory beanFactory) {
|
||||||
throws BeansException {
|
super.setBeanFactory(beanFactory);
|
||||||
this.applicationContext = applicationContext;
|
if (beanFactory instanceof ListableBeanFactory) {
|
||||||
|
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||||
|
}
|
||||||
|
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() {
|
protected void doStart() {
|
||||||
try {
|
locateAndRegisterEndpoints();
|
||||||
MBeanExporter mbeanExporter = this.applicationContext
|
|
||||||
.getBean(MBeanExporter.class);
|
|
||||||
locateAndRegisterEndpoints(mbeanExporter);
|
|
||||||
}
|
|
||||||
catch (NoSuchBeanDefinitionException nsbde) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Could not obtain MBeanExporter. No Endpoint JMX export will be attemted.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes" })
|
@SuppressWarnings({ "rawtypes" })
|
||||||
protected void locateAndRegisterEndpoints(MBeanExporter mbeanExporter) {
|
protected void locateAndRegisterEndpoints() {
|
||||||
Assert.notNull(mbeanExporter, "MBeanExporter must not be null");
|
Map<String, Endpoint> endpoints = this.beanFactory.getBeansOfType(Endpoint.class);
|
||||||
Map<String, Endpoint> endpoints = this.applicationContext
|
|
||||||
.getBeansOfType(Endpoint.class);
|
|
||||||
for (Map.Entry<String, Endpoint> endpointEntry : endpoints.entrySet()) {
|
for (Map.Entry<String, Endpoint> endpointEntry : endpoints.entrySet()) {
|
||||||
if (!this.registeredEndpoints.contains(endpointEntry.getValue())) {
|
if (!this.registeredEndpoints.contains(endpointEntry.getValue())) {
|
||||||
registerEndpoint(endpointEntry.getKey(), endpointEntry.getValue(),
|
registerEndpoint(endpointEntry.getKey(), endpointEntry.getValue());
|
||||||
mbeanExporter);
|
|
||||||
this.registeredEndpoints.add(endpointEntry.getValue());
|
this.registeredEndpoints.add(endpointEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerEndpoint(String beanName, Endpoint<?> endpoint,
|
protected void registerEndpoint(String beanName, Endpoint<?> endpoint) {
|
||||||
MBeanExporter mbeanExporter) {
|
|
||||||
try {
|
try {
|
||||||
mbeanExporter.registerManagedResource(getEndpointMBean(beanName, endpoint));
|
registerBeanNameOrInstance(getEndpointMBean(beanName, endpoint), beanName);
|
||||||
}
|
}
|
||||||
catch (MBeanExportException ex) {
|
catch (MBeanExportException ex) {
|
||||||
logger.error("Could not register MBean for endpoint [" + beanName + "]", 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);
|
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
|
// SmartLifeCycle implementation
|
||||||
|
|
||||||
public final int getPhase() {
|
public final int getPhase() {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,24 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure;
|
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.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
|
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.EnableMBeanExport;
|
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.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
@ -53,7 +64,10 @@ public class EndpointMBeanExportAutoConfigurationTests {
|
||||||
|
|
||||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||||
public void testEndpointMBeanExporterIsNotInstalled() {
|
public void testEndpointMBeanExporterIsNotInstalled() {
|
||||||
|
MockEnvironment environment = new MockEnvironment();
|
||||||
|
environment.setProperty("endpoints.jmx.enabled", "false");
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
this.context.setEnvironment(environment);
|
||||||
this.context.register(EndpointAutoConfiguration.class,
|
this.context.register(EndpointAutoConfiguration.class,
|
||||||
EndpointMBeanExportAutoConfiguration.class);
|
EndpointMBeanExportAutoConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
|
|
@ -61,6 +75,35 @@ public class EndpointMBeanExportAutoConfigurationTests {
|
||||||
fail();
|
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
|
@Configuration
|
||||||
@EnableMBeanExport
|
@EnableMBeanExport
|
||||||
public static class TestConfiguration {
|
public static class TestConfiguration {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
package org.springframework.boot.actuate.endpoint.jmx;
|
package org.springframework.boot.actuate.endpoint.jmx;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.management.MBeanInfo;
|
import javax.management.MBeanInfo;
|
||||||
import javax.management.MalformedObjectNameException;
|
import javax.management.MalformedObjectNameException;
|
||||||
|
|
@ -27,10 +30,11 @@ import org.junit.Test;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.jmx.export.MBeanExporter;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
@ -58,20 +62,15 @@ public class EndpointMBeanExporterTests {
|
||||||
new RootBeanDefinition(EndpointMBeanExporter.class));
|
new RootBeanDefinition(EndpointMBeanExporter.class));
|
||||||
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||||
TestEndpoint.class));
|
TestEndpoint.class));
|
||||||
this.context.registerBeanDefinition(
|
|
||||||
"mbeanExporter",
|
|
||||||
new RootBeanDefinition(MBeanExporter.class, null,
|
|
||||||
new MutablePropertyValues(Collections.singletonMap(
|
|
||||||
"ensureUniqueRuntimeObjectNames", "false"))));
|
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
|
|
||||||
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
|
MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class);
|
||||||
|
|
||||||
MBeanInfo mbeanInfo = mbeanExporter.getServer().getMBeanInfo(
|
MBeanInfo mbeanInfo = mbeanExporter.getServer().getMBeanInfo(
|
||||||
getObjectName("endpoint1", this.context));
|
getObjectName("endpoint1", this.context));
|
||||||
assertNotNull(mbeanInfo);
|
assertNotNull(mbeanInfo);
|
||||||
assertEquals(5, mbeanInfo.getOperations().length);
|
assertEquals(3, mbeanInfo.getOperations().length);
|
||||||
assertEquals(5, mbeanInfo.getAttributes().length);
|
assertEquals(3, mbeanInfo.getAttributes().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -83,14 +82,9 @@ public class EndpointMBeanExporterTests {
|
||||||
TestEndpoint.class));
|
TestEndpoint.class));
|
||||||
this.context.registerBeanDefinition("endpoint2", new RootBeanDefinition(
|
this.context.registerBeanDefinition("endpoint2", new RootBeanDefinition(
|
||||||
TestEndpoint.class));
|
TestEndpoint.class));
|
||||||
this.context.registerBeanDefinition(
|
|
||||||
"mbeanExporter",
|
|
||||||
new RootBeanDefinition(MBeanExporter.class, null,
|
|
||||||
new MutablePropertyValues(Collections.singletonMap(
|
|
||||||
"ensureUniqueRuntimeObjectNames", "false"))));
|
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
|
|
||||||
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
|
MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class);
|
||||||
|
|
||||||
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
||||||
getObjectName("endpoint1", this.context)));
|
getObjectName("endpoint1", this.context)));
|
||||||
|
|
@ -98,6 +92,69 @@ public class EndpointMBeanExporterTests {
|
||||||
getObjectName("endpoint2", this.context)));
|
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
|
@Test
|
||||||
public void testRegistrationWithParentContext() throws Exception {
|
public void testRegistrationWithParentContext() throws Exception {
|
||||||
this.context = new GenericApplicationContext();
|
this.context = new GenericApplicationContext();
|
||||||
|
|
@ -105,19 +162,13 @@ public class EndpointMBeanExporterTests {
|
||||||
new RootBeanDefinition(EndpointMBeanExporter.class));
|
new RootBeanDefinition(EndpointMBeanExporter.class));
|
||||||
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
this.context.registerBeanDefinition("endpoint1", new RootBeanDefinition(
|
||||||
TestEndpoint.class));
|
TestEndpoint.class));
|
||||||
this.context.registerBeanDefinition(
|
|
||||||
"mbeanExporter",
|
|
||||||
new RootBeanDefinition(MBeanExporter.class, null,
|
|
||||||
new MutablePropertyValues(Collections.singletonMap(
|
|
||||||
"ensureUniqueRuntimeObjectNames", "false"))));
|
|
||||||
|
|
||||||
GenericApplicationContext parent = new GenericApplicationContext();
|
GenericApplicationContext parent = new GenericApplicationContext();
|
||||||
|
|
||||||
this.context.setParent(parent);
|
this.context.setParent(parent);
|
||||||
parent.refresh();
|
parent.refresh();
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
|
|
||||||
MBeanExporter mbeanExporter = this.context.getBean(MBeanExporter.class);
|
MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class);
|
||||||
|
|
||||||
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
assertNotNull(mbeanExporter.getServer().getMBeanInfo(
|
||||||
getObjectName("endpoint1", this.context)));
|
getObjectName("endpoint1", this.context)));
|
||||||
|
|
@ -125,10 +176,25 @@ public class EndpointMBeanExporterTests {
|
||||||
parent.close();
|
parent.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectName getObjectName(String beanKey, ApplicationContext applicationContext)
|
private ObjectName getObjectName(String beanKey, GenericApplicationContext context)
|
||||||
throws MalformedObjectNameException {
|
throws MalformedObjectNameException {
|
||||||
return new DataEndpointMBean(beanKey,
|
return getObjectName("org.springframework.boot", beanKey, false, context);
|
||||||
(Endpoint<?>) applicationContext.getBean(beanKey)).getObjectName();
|
}
|
||||||
|
|
||||||
|
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> {
|
public static class TestEndpoint extends AbstractEndpoint<String> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue