Browse Source

polishing

Reorganized class structure to match our code style (setter for
properties at the top of the class, public method before private
implementation).

Removed DisposableBean as it the lifecycle is already taking care
of removing MBeans on stop.

Cleaned test suite

Issue: SPR-8045
pull/556/merge
Stephane Nicoll 11 years ago
parent
commit
c7b106577f
  1. 161
      spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java
  2. 12
      spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java
  3. 2
      spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java
  4. 286
      spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java
  5. 24
      spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java
  6. 2
      spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java
  7. 6
      spring-context/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml
  8. 6
      spring-context/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml
  9. 17
      spring-context/src/test/resources/org/springframework/jmx/export/autodetectNoAutoStartup.xml
  10. 7
      src/asciidoc/index.adoc

161
spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java

@ -46,7 +46,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware; @@ -46,7 +46,6 @@ 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;
@ -68,7 +67,6 @@ import org.springframework.util.ClassUtils; @@ -68,7 +67,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
/**
* JMX exporter that allows for exposing any <i>Spring-managed bean</i> to a
* JMX {@link javax.management.MBeanServer}, without the need to define any
@ -91,6 +89,8 @@ import org.springframework.util.ObjectUtils; @@ -91,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
@ -100,7 +100,7 @@ import org.springframework.util.ObjectUtils; @@ -100,7 +100,7 @@ import org.springframework.util.ObjectUtils;
* @see MBeanExporterListener
*/
public class MBeanExporter extends MBeanRegistrationSupport
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean, SmartLifecycle {
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, SmartLifecycle {
/**
* Autodetection mode indicating that no autodetection should be used.
@ -405,16 +405,31 @@ public class MBeanExporter extends MBeanRegistrationSupport @@ -405,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
@ -424,15 +439,56 @@ public class MBeanExporter extends MBeanRegistrationSupport @@ -424,15 +439,56 @@ public class MBeanExporter extends MBeanRegistrationSupport
}
}
/**
* 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 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;
}
}
running = true;
}
@Override
public void stop() {
logger.info("Unregistering JMX-exposed beans on stop");
synchronized (this.lifecycleMonitor) {
unregisterNotificationListeners();
unregisterBeans();
running = false;
}
}
@Override
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;
}
@ -1053,79 +1109,6 @@ public class MBeanExporter extends MBeanRegistrationSupport @@ -1053,79 +1109,6 @@ public class MBeanExporter extends MBeanRegistrationSupport
}
}
/**
* Set whether to automatically start the container 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;
}
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
@Override
public void stop(Runnable callback) {
synchronized (this.lifecycleMonitor) {
stop();
callback.run();
}
}
@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;
}
}
running = true;
}
@Override
public void stop() {
logger.info("Unregistering JMX-exposed beans on stop");
synchronized (this.lifecycleMonitor) {
unregisterNotificationListeners();
unregisterBeans();
running = false;
}
}
@Override
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
/**
* Specify the phase in which this container should be started and
* stopped. The startup order proceeds from lowest to highest, and
* the shutdown order is the reverse of that. By default this value
* is Integer.MAX_VALUE meaning that this container starts as late
* as possible and stops as soon as possible.
*/
public void setPhase(int phase) {
this.phase = phase;
}
@Override
public int getPhase() {
return this.phase;
}
//---------------------------------------------------------------------
// Inner classes for internal use
//---------------------------------------------------------------------

12
spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java

@ -25,6 +25,7 @@ import org.junit.Before; @@ -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 { @@ -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));
}

2
spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java

@ -67,7 +67,7 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests { @@ -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 {

286
spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java

@ -33,11 +33,16 @@ import javax.management.ObjectInstance; @@ -33,11 +33,16 @@ 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;
@ -63,10 +68,14 @@ import static org.junit.Assert.*; @@ -63,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" })
@ -76,12 +85,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -76,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" })
@ -91,12 +97,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -91,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" })
@ -116,9 +119,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -116,9 +119,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setServer(server);
exporter.setNotificationListenerMappings(listeners);
try {
exporter.afterPropertiesSet();
exporter.start();
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));
@ -130,22 +133,15 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -130,22 +133,15 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(getBeanMap());
exporter.setServer(server);
exporter.afterPropertiesSet();
exporter.start();
assertIsRegistered("The bean was not registered with the MBeanServer",
ObjectNameManager.getInstance(OBJECT_NAME));
}
/** 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));
try {
start(exporter);
assertIsRegistered("The bean was not registered with the MBeanServer",
ObjectNameManager.getInstance(OBJECT_NAME));
}
finally {
exporter.stop();
}
}
*/
@Test
public void testUserCreatedMBeanRegWithDynamicMBean() throws Exception {
@ -158,22 +154,24 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -158,22 +154,24 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setServer(server);
exporter.setBeans(map);
exporter.setAssembler(asm);
exporter.afterPropertiesSet();
exporter.start();
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 {
GenericApplicationContext ctx = new GenericApplicationContext();
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
ctx.refresh();
ConfigurableApplicationContext ctx = load("autodetectMBeans.xml");
try {
ctx.getBean("exporter");
MBeanServer server = (MBeanServer) ctx.getBean("server");
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"));
@ -181,39 +179,32 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -181,39 +179,32 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean3=true"));
assertNotNull(instance);
} finally {
ctx.destroy();
ctx.close();
}
}
@Test
public void testAutodetectWithExclude() throws Exception {
GenericApplicationContext ctx = new GenericApplicationContext();
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(new ClassPathResource("autodetectMBeans.xml", getClass()));
ctx.refresh();
ConfigurableApplicationContext ctx = load("autodetectMBeans.xml");
try {
ctx.getBean("exporter");
MBeanServer server = (MBeanServer) ctx.getBean("server");
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 {
ctx.destroy();
ctx.close();
}
}
@Test
public void testAutodetectLazyMBeans() throws Exception {
GenericApplicationContext ctx = new GenericApplicationContext();
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(new ClassPathResource("autodetectLazyMBeans.xml", getClass()));
ctx.refresh();
ConfigurableApplicationContext ctx = load("autodetectLazyMBeans.xml");
try {
ctx.getBean("exporter");
MBeanServer server = (MBeanServer) ctx.getBean("server");
MBeanServer server = ctx.getBean("server", MBeanServer.class);
ObjectName oname = ObjectNameManager.getInstance("spring:mbean=true");
assertNotNull(server.getObjectInstance(oname));
@ -225,19 +216,41 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -225,19 +216,41 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
name = (String) server.getAttribute(oname, "Name");
assertEquals("Invalid name returned", "Juergen Hoeller", name);
} finally {
ctx.destroy();
ctx.close();
}
}
@Test
public void testAutodetectNoMBeans() throws Exception {
GenericApplicationContext ctx = new GenericApplicationContext();
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(new ClassPathResource("autodetectNoMBeans.xml", getClass()));
ctx.refresh();
ConfigurableApplicationContext ctx = load("autodetectNoMBeans.xml");
try {
ctx.getBean("exporter");
} finally {
ctx.destroy();
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();
}
}
@ -250,14 +263,14 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -250,14 +263,14 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setBeans(getBeanMap());
exporter.setServer(server);
exporter.setListeners(new MBeanExporterListener[] { listener1, listener2 });
exporter.afterPropertiesSet();
exporter.start();
exporter.destroy();
start(exporter);
exporter.stop();
assertListener(listener1);
assertListener(listener2);
}
@Test
public void testExportJdkProxy() throws Exception {
JmxTestBean bean = new JmxTestBean();
@ -297,8 +310,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -297,8 +310,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setServer(server);
exporter.setBeans(beans);
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
ObjectInstance instance = server.getObjectInstance(objectName);
assertNotNull(instance);
@ -327,8 +339,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -327,8 +339,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setBeans(beans);
exporter.setRegistrationBehavior(MBeanExporter.REGISTRATION_IGNORE_EXISTING);
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
ObjectInstance instance = server.getObjectInstance(objectName);
assertNotNull(instance);
@ -359,8 +370,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -359,8 +370,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setBeans(beans);
exporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING);
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
ObjectInstance instance = server.getObjectInstance(objectName);
assertNotNull(instance);
@ -385,13 +395,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -385,13 +395,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setServer(getServer());
exporter.setBeans(beans);
exporter.setExposeManagedResourceClassLoader(true);
exporter.afterPropertiesSet();
exporter.start();
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"));
@ -416,8 +425,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -416,8 +425,7 @@ 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();
exporter.start();
start(exporter);
}
@ -434,8 +442,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -434,8 +442,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_MBEAN);
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
assertIsRegistered("Bona fide MBean not autodetected in AUTODETECT_MBEAN mode",
ObjectNameManager.getInstance(OBJECT_NAME));
@ -458,8 +465,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -458,8 +465,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
assertIsRegistered("Bona fide MBean not autodetected in (AUTODETECT_ALL) mode",
ObjectNameManager.getInstance(OBJECT_NAME));
assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode",
@ -481,8 +487,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -481,8 +487,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(exportedBeanName));
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER);
exporter.afterPropertiesSet();
exporter.start();
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",
@ -506,104 +511,69 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -506,104 +511,69 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(OBJECT_NAME));
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ASSEMBLER);
exporter.afterPropertiesSet();
exporter.start();
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();
exporter.start();
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();
exporter.start();
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);
}
/**
@ -616,13 +586,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -616,13 +586,12 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setServer(this.server);
MockMBeanExporterListener listener = new MockMBeanExporterListener();
exporter.setListeners(new MBeanExporterListener[] { listener });
exporter.afterPropertiesSet();
exporter.start();
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());
}
@ -649,7 +618,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -649,7 +618,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
StubNotificationListener listener = new StubNotificationListener();
exporter.setNotificationListenerMappings(Collections.singletonMap(beanName, listener));
exporter.afterPropertiesSet();
start(exporter);
}
@Test
@ -671,7 +640,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -671,7 +640,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
StubNotificationListener listener = new StubNotificationListener();
exporter.setNotificationListenerMappings(Collections.singletonMap("*", listener));
exporter.afterPropertiesSet();
start(exporter);
}
/*
@ -699,8 +668,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -699,8 +668,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
exporter.setBeanFactory(factory);
try {
exporter.afterPropertiesSet();
exporter.start();
start(exporter);
fail("Must have failed during creation of RuntimeExceptionThrowingConstructorBean");
}
catch (RuntimeException expected) {
@ -712,6 +680,10 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { @@ -712,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());

24
spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java

@ -61,7 +61,7 @@ public class NotificationListenerTests extends AbstractMBeanServerTests { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();

2
spring-context/src/test/java/org/springframework/jmx/export/assembler/AbstractMetadataAssemblerTests.java

@ -175,7 +175,7 @@ public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemble @@ -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);

6
spring-context/src/test/java/org/springframework/jmx/export/autodetectLazyMBeans.xml

@ -17,10 +17,4 @@ @@ -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>

6
spring-context/src/test/java/org/springframework/jmx/export/autodetectMBeans.xml

@ -17,12 +17,6 @@ @@ -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"/>

17
spring-context/src/test/resources/org/springframework/jmx/export/autodetectNoAutoStartup.xml

@ -0,0 +1,17 @@ @@ -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>

7
src/asciidoc/index.adoc

@ -41809,6 +41809,13 @@ With this configuration the `testBean` bean is exposed as an MBean under the @@ -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]]

Loading…
Cancel
Save