Merge pull request #551 from mdeinum/SPR-8045
* SPR-8045: polishing Using SmartLifecycle to register MBeans
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,11 +46,11 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler;
|
||||
import org.springframework.jmx.export.assembler.MBeanInfoAssembler;
|
||||
@@ -89,6 +89,8 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Juergen Hoeller
|
||||
* @author Rick Evans
|
||||
* @author Mark Fisher
|
||||
* @author Marten Deinum
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.2
|
||||
* @see #setBeans
|
||||
* @see #setAutodetect
|
||||
@@ -98,7 +100,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @see MBeanExporterListener
|
||||
*/
|
||||
public class MBeanExporter extends MBeanRegistrationSupport
|
||||
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
|
||||
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, SmartLifecycle {
|
||||
|
||||
/**
|
||||
* Autodetection mode indicating that no autodetection should be used.
|
||||
@@ -178,6 +180,14 @@ public class MBeanExporter extends MBeanRegistrationSupport
|
||||
/** Stores the BeanFactory for use in autodetection process */
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private boolean autoStartup = true;
|
||||
|
||||
private volatile boolean running = false;
|
||||
|
||||
private int phase = Integer.MAX_VALUE;
|
||||
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Supply a {@code Map} of beans to be registered with the JMX
|
||||
@@ -395,16 +405,31 @@ public class MBeanExporter extends MBeanRegistrationSupport
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the phase in which the MBeans should be exported to the
|
||||
* JMX domain. The startup order proceeds from lowest to highest, and
|
||||
* the shutdown order is the reverse of that. By default this value
|
||||
* is {@code Integer.MAX_VALUE} meaning that MBeans are exported
|
||||
* as late as possible and removed from the domain as soon as possible.
|
||||
*/
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to automatically export MBeans after initialization.
|
||||
* <p>Default is "true"; set this to "false" to allow for manual startup
|
||||
* through the {@link #start()} method.
|
||||
*/
|
||||
public void setAutoStartup(boolean autoStartup) {
|
||||
this.autoStartup = autoStartup;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Lifecycle in bean factory: automatically register/unregister beans
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Start bean registration automatically when deployed in an
|
||||
* {@code ApplicationContext}.
|
||||
* @see #registerBeans()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// If no server was provided then try to find one. This is useful in an environment
|
||||
@@ -412,28 +437,58 @@ public class MBeanExporter extends MBeanRegistrationSupport
|
||||
if (this.server == null) {
|
||||
this.server = JmxUtils.locateMBeanServer();
|
||||
}
|
||||
try {
|
||||
logger.info("Registering beans for JMX exposure on startup");
|
||||
registerBeans();
|
||||
registerNotificationListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
logger.info("Registering beans for JMX exposure");
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
try {
|
||||
registerBeans();
|
||||
registerNotificationListeners();
|
||||
} catch (RuntimeException ex) {
|
||||
// Unregister beans already registered by this exporter.
|
||||
unregisterNotificationListeners();
|
||||
unregisterBeans();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
// Unregister beans already registered by this exporter.
|
||||
running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.info("Unregistering JMX-exposed beans on stop");
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
unregisterNotificationListeners();
|
||||
unregisterBeans();
|
||||
throw ex;
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all beans that this exported has exposed via JMX
|
||||
* when the enclosing {@code ApplicationContext} is destroyed.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
logger.info("Unregistering JMX-exposed beans on shutdown");
|
||||
unregisterNotificationListeners();
|
||||
unregisterBeans();
|
||||
public void stop(Runnable callback) {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
return this.running;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return this.autoStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return this.phase;
|
||||
}
|
||||
|
||||
|
||||
@@ -1054,7 +1109,6 @@ public class MBeanExporter extends MBeanRegistrationSupport
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Inner classes for internal use
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.junit.Before;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.jmx.export.MBeanExporter;
|
||||
import org.springframework.tests.TestGroup;
|
||||
import org.springframework.util.MBeanTestUtils;
|
||||
|
||||
@@ -91,6 +92,17 @@ public abstract class AbstractMBeanServerTests {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the specified {@link MBeanExporter}.
|
||||
*
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
*/
|
||||
protected void start(MBeanExporter exporter) {
|
||||
exporter.afterPropertiesSet();
|
||||
exporter.start();
|
||||
}
|
||||
|
||||
protected void assertIsRegistered(String message, ObjectName objectName) {
|
||||
assertTrue(message, getServer().isRegistered(objectName));
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests {
|
||||
adapter.setServer(getServer());
|
||||
adapter.setBeans(beans);
|
||||
adapter.setAssembler(new ProxyTestAssembler());
|
||||
adapter.afterPropertiesSet();
|
||||
start(adapter);
|
||||
}
|
||||
|
||||
protected MBeanServerConnection getServerConnection() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,11 +33,17 @@ import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.modelmbean.ModelMBeanInfo;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jmx.AbstractMBeanServerTests;
|
||||
import org.springframework.jmx.IJmxTestBean;
|
||||
@@ -62,10 +68,14 @@ import static org.junit.Assert.*;
|
||||
* @author Mark Fisher
|
||||
* @author Chris Beams
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor";
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@@ -75,12 +85,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
// put a non-NotificationListener instance in as a value...
|
||||
listeners.put("*", this);
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
try {
|
||||
exporter.setNotificationListenerMappings(listeners);
|
||||
fail("Must have thrown a ClassCastException when registering a non-NotificationListener instance as a NotificationListener.");
|
||||
}
|
||||
catch (ClassCastException expected) {
|
||||
}
|
||||
|
||||
thrown.expect(ClassCastException.class);
|
||||
exporter.setNotificationListenerMappings(listeners);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@@ -90,12 +97,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
// put null in as a value...
|
||||
listeners.put("*", null);
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
try {
|
||||
exporter.setNotificationListenerMappings(listeners);
|
||||
fail("Must have thrown an IllegalArgumentException when registering a null instance as a NotificationListener.");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setNotificationListenerMappings(listeners);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@@ -115,8 +119,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setNotificationListenerMappings(listeners);
|
||||
try {
|
||||
exporter.afterPropertiesSet();
|
||||
fail("Must have thrown an MBeanExportException when registering a NotificationListener on a non-existent MBean.");
|
||||
start(exporter);
|
||||
fail("Must have thrown an MBeanExportException when registering a " +
|
||||
"NotificationListener on a non-existent MBean.");
|
||||
}
|
||||
catch (MBeanExportException expected) {
|
||||
assertTrue(expected.contains(InstanceNotFoundException.class));
|
||||
@@ -128,22 +133,16 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setBeans(getBeanMap());
|
||||
exporter.setServer(server);
|
||||
exporter.afterPropertiesSet();
|
||||
assertIsRegistered("The bean was not registered with the MBeanServer",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
try {
|
||||
start(exporter);
|
||||
assertIsRegistered("The bean was not registered with the MBeanServer",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
}
|
||||
finally {
|
||||
exporter.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/** Fails if JVM platform MBean server has been started already
|
||||
@Test
|
||||
public void testWithLocatedMBeanServer() throws Exception {
|
||||
MBeanExporter adaptor = new MBeanExporter();
|
||||
adaptor.setBeans(getBeanMap());
|
||||
adaptor.afterPropertiesSet();
|
||||
assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
server.unregisterMBean(new ObjectName(OBJECT_NAME));
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
@@ -155,20 +154,24 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(map);
|
||||
exporter.setAssembler(asm);
|
||||
exporter.afterPropertiesSet();
|
||||
|
||||
Object name = server.getAttribute(ObjectNameManager.getInstance("spring:name=dynBean"), "Name");
|
||||
assertEquals("The name attribute is incorrect", "Rob Harrop", name);
|
||||
assertFalse("Assembler should not have been invoked", asm.invoked);
|
||||
try {
|
||||
start(exporter);
|
||||
Object name = server.getAttribute(ObjectNameManager.getInstance("spring:name=dynBean"), "Name");
|
||||
assertEquals("The name attribute is incorrect", "Rob Harrop", name);
|
||||
assertFalse("Assembler should not have been invoked", asm.invoked);
|
||||
}
|
||||
finally {
|
||||
exporter.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutodetectMBeans() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
|
||||
ConfigurableApplicationContext ctx = load("autodetectMBeans.xml");
|
||||
try {
|
||||
bf.getBean("exporter");
|
||||
MBeanServer server = (MBeanServer) bf.getBean("server");
|
||||
ctx.getBean("exporter");
|
||||
MBeanServer server = ctx.getBean("server", MBeanServer.class);
|
||||
ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true"));
|
||||
assertNotNull(instance);
|
||||
instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean2=true"));
|
||||
@@ -176,37 +179,32 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean3=true"));
|
||||
assertNotNull(instance);
|
||||
} finally {
|
||||
bf.destroySingletons();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutodetectWithExclude() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
|
||||
ConfigurableApplicationContext ctx = load("autodetectMBeans.xml");
|
||||
try {
|
||||
bf.getBean("exporter");
|
||||
MBeanServer server = (MBeanServer) bf.getBean("server");
|
||||
ctx.getBean("exporter");
|
||||
MBeanServer server = ctx.getBean("server", MBeanServer.class);
|
||||
ObjectInstance instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=true"));
|
||||
assertNotNull(instance);
|
||||
|
||||
try {
|
||||
server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=false"));
|
||||
fail("MBean with name spring:mbean=false should have been excluded");
|
||||
} catch (InstanceNotFoundException expected) {
|
||||
}
|
||||
thrown.expect(InstanceNotFoundException.class);
|
||||
server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=false"));
|
||||
} finally {
|
||||
bf.destroySingletons();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutodetectLazyMBeans() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectLazyMBeans.xml", getClass()));
|
||||
ConfigurableApplicationContext ctx = load("autodetectLazyMBeans.xml");
|
||||
try {
|
||||
bf.getBean("exporter");
|
||||
MBeanServer server = (MBeanServer) bf.getBean("server");
|
||||
ctx.getBean("exporter");
|
||||
MBeanServer server = ctx.getBean("server", MBeanServer.class);
|
||||
|
||||
ObjectName oname = ObjectNameManager.getInstance("spring:mbean=true");
|
||||
assertNotNull(server.getObjectInstance(oname));
|
||||
@@ -218,18 +216,41 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
name = (String) server.getAttribute(oname, "Name");
|
||||
assertEquals("Invalid name returned", "Juergen Hoeller", name);
|
||||
} finally {
|
||||
bf.destroySingletons();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutodetectNoMBeans() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectNoMBeans.xml", getClass()));
|
||||
ConfigurableApplicationContext ctx = load("autodetectNoMBeans.xml");
|
||||
try {
|
||||
bf.getBean("exporter");
|
||||
ctx.getBean("exporter");
|
||||
} finally {
|
||||
bf.destroySingletons();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoStartupToFalse() throws Exception {
|
||||
ConfigurableApplicationContext ctx = load("autodetectNoAutoStartup.xml");
|
||||
try {
|
||||
MBeanExporter exporter = ctx.getBean("exporter", MBeanExporter.class);
|
||||
MBeanServer server = ctx.getBean("server", MBeanServer.class);
|
||||
|
||||
ObjectName on = ObjectNameManager.getInstance("spring:mbean=true");
|
||||
try {
|
||||
server.getObjectInstance(on);
|
||||
fail("MBeans should not have been exported with autoStartup set to false");
|
||||
}
|
||||
catch (InstanceNotFoundException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// Export manually
|
||||
exporter.start();
|
||||
assertNotNull(server.getObjectInstance(on)); // Should be exposed now.
|
||||
} finally {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,13 +263,14 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(getBeanMap());
|
||||
exporter.setServer(server);
|
||||
exporter.setListeners(new MBeanExporterListener[] { listener1, listener2 });
|
||||
exporter.afterPropertiesSet();
|
||||
exporter.destroy();
|
||||
start(exporter);
|
||||
exporter.stop();
|
||||
|
||||
assertListener(listener1);
|
||||
assertListener(listener2);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExportJdkProxy() throws Exception {
|
||||
JmxTestBean bean = new JmxTestBean();
|
||||
@@ -288,7 +310,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
ObjectInstance instance = server.getObjectInstance(objectName);
|
||||
assertNotNull(instance);
|
||||
@@ -317,7 +339,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setRegistrationBehavior(MBeanExporter.REGISTRATION_IGNORE_EXISTING);
|
||||
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
ObjectInstance instance = server.getObjectInstance(objectName);
|
||||
assertNotNull(instance);
|
||||
@@ -348,7 +370,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING);
|
||||
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
ObjectInstance instance = server.getObjectInstance(objectName);
|
||||
assertNotNull(instance);
|
||||
@@ -373,12 +395,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(getServer());
|
||||
exporter.setBeans(beans);
|
||||
exporter.setExposeManagedResourceClassLoader(true);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
assertIsRegistered("Bean instance not registered", objectName);
|
||||
|
||||
Object result = server.invoke(objectName, "add", new Object[] { new Integer(2), new Integer(3) }, new String[] {
|
||||
int.class.getName(), int.class.getName() });
|
||||
Object result = server.invoke(objectName, "add", new Object[] {new Integer(2), new Integer(3)}, new String[] {
|
||||
int.class.getName(), int.class.getName()});
|
||||
|
||||
assertEquals("Incorrect result return from add", result, new Integer(5));
|
||||
assertEquals("Incorrect attribute value", name, server.getAttribute(objectName, "Name"));
|
||||
@@ -403,7 +425,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_NONE);
|
||||
// MBean has a bad ObjectName, so if said MBean is autodetected, an exception will be thrown...
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -419,7 +442,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_MBEAN);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
assertIsRegistered("Bona fide MBean not autodetected in AUTODETECT_MBEAN mode",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
assertIsNotRegistered("Bean autodetected and (only) AUTODETECT_MBEAN mode is on",
|
||||
@@ -441,7 +465,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Bona fide MBean not autodetected in (AUTODETECT_ALL) mode",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode",
|
||||
@@ -463,7 +487,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsNotRegistered("Bona fide MBean was autodetected in AUTODETECT_ASSEMBLER mode - must not have been",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
assertIsRegistered("Bean not autodetected in AUTODETECT_ASSEMBLER mode",
|
||||
@@ -487,101 +511,69 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(OBJECT_NAME));
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Explicitly exported bona fide MBean obviously not exported.",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeToOutOfRangeNegativeValue() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectMode(-1);
|
||||
fail("Must have failed when supplying an invalid negative out-of-range autodetect mode");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeToOutOfRangeNegativeValue() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectMode(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeToOutOfRangePositiveValue() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectMode(5);
|
||||
fail("Must have failed when supplying an invalid positive out-of-range autodetect mode");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeToOutOfRangePositiveValue() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectMode(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeNameToNull() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectModeName(null);
|
||||
fail("Must have failed when supplying a null autodetect mode name");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeNameToNull() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectModeName(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeNameToAnEmptyString() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectModeName("");
|
||||
fail("Must have failed when supplying an empty autodetect mode name");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeNameToAnEmptyString() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectModeName("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeNameToAWhitespacedString() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectModeName(" \t");
|
||||
fail("Must have failed when supplying a whitespace-only autodetect mode name");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeNameToAWhitespacedString() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectModeName(" \t");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAutodetectModeNameToARubbishValue() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectModeName("That Hansel is... *sssooo* hot right now!");
|
||||
fail("Must have failed when supplying a whitespace-only autodetect mode name");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
public void testSetAutodetectModeNameToARubbishValue() {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
exporter.setAutodetectModeName("That Hansel is... *sssooo* hot right now!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotRunningInBeanFactoryAndPassedBeanNameToExport() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
Map<String, Object> beans = new HashMap<String, Object>();
|
||||
beans.put(OBJECT_NAME, "beanName");
|
||||
exporter.setBeans(beans);
|
||||
exporter.afterPropertiesSet();
|
||||
fail("Expecting exception because MBeanExporter is not running in a BeanFactory and was passed bean name to (lookup and then) export");
|
||||
}
|
||||
catch (MBeanExportException expected) {
|
||||
}
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
Map<String, Object> beans = new HashMap<String, Object>();
|
||||
beans.put(OBJECT_NAME, "beanName");
|
||||
exporter.setBeans(beans);
|
||||
thrown.expect(MBeanExportException.class);
|
||||
start(exporter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotRunningInBeanFactoryAndAutodetectionIsOn() throws Exception {
|
||||
try {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
|
||||
exporter.afterPropertiesSet();
|
||||
fail("Expecting exception because MBeanExporter is not running in a BeanFactory and was configured to autodetect beans");
|
||||
}
|
||||
catch (MBeanExportException expected) {
|
||||
}
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
|
||||
thrown.expect(MBeanExportException.class);
|
||||
start(exporter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,12 +586,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(this.server);
|
||||
MockMBeanExporterListener listener = new MockMBeanExporterListener();
|
||||
exporter.setListeners(new MBeanExporterListener[] { listener });
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("The bean was not registered with the MBeanServer",
|
||||
ObjectNameManager.getInstance(OBJECT_NAME));
|
||||
|
||||
this.server.unregisterMBean(new ObjectName(OBJECT_NAME));
|
||||
exporter.destroy();
|
||||
exporter.stop();
|
||||
assertEquals("Listener should not have been invoked (MBean previously unregistered by external agent)", 0,
|
||||
listener.getUnregistered().size());
|
||||
}
|
||||
@@ -626,7 +618,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
StubNotificationListener listener = new StubNotificationListener();
|
||||
exporter.setNotificationListenerMappings(Collections.singletonMap(beanName, listener));
|
||||
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -648,7 +640,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
StubNotificationListener listener = new StubNotificationListener();
|
||||
exporter.setNotificationListenerMappings(Collections.singletonMap("*", listener));
|
||||
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -676,7 +668,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeanFactory(factory);
|
||||
|
||||
try {
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
fail("Must have failed during creation of RuntimeExceptionThrowingConstructorBean");
|
||||
}
|
||||
catch (RuntimeException expected) {
|
||||
@@ -688,6 +680,10 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
|
||||
ObjectNameManager.getInstance(objectName2));
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext load(String context) {
|
||||
return new ClassPathXmlApplicationContext(context, getClass());
|
||||
}
|
||||
|
||||
private Map<String, Object> getBeanMap() {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put(OBJECT_NAME, new JmxTestBean());
|
||||
|
||||
@@ -61,7 +61,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(notificationListeners);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
// update the attribute
|
||||
String attributeName = "Name";
|
||||
@@ -87,7 +87,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(notificationListeners);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
// update the attribute
|
||||
String attributeName = "Name";
|
||||
@@ -115,7 +115,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListeners(new NotificationListenerBean[] { listenerBean });
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
// update the attribute
|
||||
String attributeName = "Name";
|
||||
@@ -143,7 +143,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListeners(new NotificationListenerBean[] { listenerBean });
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
// update the attribute
|
||||
String attributeName = "Name";
|
||||
@@ -181,7 +181,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListeners(new NotificationListenerBean[] { listenerBean });
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
// update the attributes
|
||||
String nameAttribute = "Name";
|
||||
@@ -227,7 +227,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(listenerMappings);
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Should have registered MBean", objectName);
|
||||
|
||||
server.setAttribute(objectName, new Attribute("Age", new Integer(77)));
|
||||
@@ -258,7 +258,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(listenerMappings);
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Should have registered MBean", objectName);
|
||||
|
||||
server.setAttribute(objectName, new Attribute("Age", new Integer(77)));
|
||||
@@ -290,7 +290,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(listenerMappings);
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Should have registered MBean", objectName);
|
||||
|
||||
server.setAttribute(objectName, new Attribute("Age", new Integer(77)));
|
||||
@@ -322,7 +322,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(listenerMappings);
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Should have registered MBean", objectName);
|
||||
|
||||
server.setAttribute(objectName, new Attribute("Age", new Integer(77)));
|
||||
@@ -362,7 +362,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
exporter.setBeans(beans);
|
||||
exporter.setNotificationListenerMappings(listenerMappings);
|
||||
exporter.setBeanFactory(factory);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
assertIsRegistered("Should have registered MBean", objectName1);
|
||||
assertIsRegistered("Should have registered MBean", objectName2);
|
||||
|
||||
@@ -384,7 +384,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener();
|
||||
|
||||
@@ -420,7 +420,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests {
|
||||
MBeanExporter exporter = new MBeanExporter();
|
||||
exporter.setServer(server);
|
||||
exporter.setBeans(beans);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
CountingAttributeChangeNotificationListener listener = new CountingAttributeChangeNotificationListener();
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemble
|
||||
Map<String, Object> beans = new HashMap<String, Object>();
|
||||
beans.put(objectName, proxy);
|
||||
exporter.setBeans(beans);
|
||||
exporter.afterPropertiesSet();
|
||||
start(exporter);
|
||||
|
||||
MBeanInfo inf = getServer().getMBeanInfo(ObjectNameManager.getInstance(objectName));
|
||||
assertEquals("Incorrect number of operations", getExpectedOperationCount(), inf.getOperations().length);
|
||||
|
||||
@@ -17,10 +17,4 @@
|
||||
<property name="name" value="Juergen Hoeller"/>
|
||||
</bean>
|
||||
|
||||
<bean id="connector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
|
||||
<property name="server">
|
||||
<ref local="server"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
|
||||
<bean name="spring:mbean3=true" class="org.springframework.jmx.export.TestDynamicMBean"/>
|
||||
|
||||
<bean id="connector" class="org.springframework.jmx.support.ConnectorServerFactoryBean">
|
||||
<property name="server">
|
||||
<ref local="server"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="toBeIgnored" class="javax.management.DynamicMBean" abstract="true"/>
|
||||
|
||||
<bean id="toBeIgnoredToo" class="javax.management.DynamicMBean" abstract="true" lazy-init="true"/>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="server" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
|
||||
|
||||
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
|
||||
<property name="server" ref="server"/>
|
||||
<property name="autodetect" value="true"/>
|
||||
<property name="autoStartup" value="false"/>
|
||||
</bean>
|
||||
|
||||
<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -41809,6 +41809,13 @@ With this configuration the `testBean` bean is exposed as an MBean under the
|
||||
are exposed as attributes and all __public__ methods (bar those inherited from the
|
||||
`Object` class) are exposed as operations.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
`MBeanExporter` is a `Lifecycle` bean (see <<beans-factory-lifecycle-processor>>)
|
||||
and MBeans are exported as late as possible during the application lifecycle by default. It
|
||||
is possible to configure the `phase` at which the export happens or disable automatic
|
||||
registration by setting the `autoStartup` flag.
|
||||
====
|
||||
|
||||
|
||||
[[jmx-exporting-mbeanserver]]
|
||||
|
||||
Reference in New Issue
Block a user