diff --git a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java index 813bcf0aa38..12d0a24b52a 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java @@ -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. @@ -25,7 +25,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; - import javax.management.DynamicMBean; import javax.management.JMException; import javax.management.MBeanException; @@ -82,8 +81,7 @@ import org.springframework.util.ObjectUtils; * via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing * application code to be notified of MBean registration and unregistration events. * - *

This exporter is compatible with JMX 1.2 on Java 5 and above. - * As of Spring 2.5, it also autodetects and exports Java 6 MXBeans. + *

This exporter is compatible with MBeans and MXBeans on Java 6 and above. * * @author Rob Harrop * @author Juergen Hoeller @@ -97,8 +95,8 @@ import org.springframework.util.ObjectUtils; * @see org.springframework.jmx.export.assembler.MBeanInfoAssembler * @see MBeanExporterListener */ -public class MBeanExporter extends MBeanRegistrationSupport - implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { +public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExportOperations, + BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { /** * Autodetection mode indicating that no autodetection should be used. @@ -147,6 +145,12 @@ public class MBeanExporter extends MBeanRegistrationSupport /** Whether to eagerly initialize candidate beans when autodetecting MBeans */ private boolean allowEagerInit = false; + /** Stores the MBeanInfoAssembler to use for this exporter */ + private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler(); + + /** The strategy to use for creating ObjectNames for an object */ + private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy(); + /** Indicates whether Spring should modify generated ObjectNames */ private boolean ensureUniqueRuntimeObjectNames = true; @@ -166,12 +170,6 @@ public class MBeanExporter extends MBeanRegistrationSupport private final Map registeredNotificationListeners = new LinkedHashMap(); - /** Stores the MBeanInfoAssembler to use for this exporter */ - private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler(); - - /** The strategy to use for creating ObjectNames for an object */ - private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy(); - /** Stores the ClassLoader to use for generating lazy-init proxies */ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); @@ -284,22 +282,6 @@ public class MBeanExporter extends MBeanRegistrationSupport this.namingStrategy = namingStrategy; } - /** - * Set the {@code MBeanExporterListener}s that should be notified - * of MBean registration and unregistration events. - * @see MBeanExporterListener - */ - public void setListeners(MBeanExporterListener[] listeners) { - this.listeners = listeners; - } - - /** - * Set the list of names for beans that should be excluded from autodetection. - */ - public void setExcludedBeans(String[] excludedBeans) { - this.excludedBeans = (excludedBeans != null ? new HashSet(Arrays.asList(excludedBeans)) : null); - } - /** * Indicates whether Spring should ensure that {@link ObjectName ObjectNames} * generated by the configured {@link ObjectNamingStrategy} for @@ -325,6 +307,22 @@ public class MBeanExporter extends MBeanRegistrationSupport this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader; } + /** + * Set the list of names for beans that should be excluded from autodetection. + */ + public void setExcludedBeans(String... excludedBeans) { + this.excludedBeans = (excludedBeans != null ? new HashSet(Arrays.asList(excludedBeans)) : null); + } + + /** + * Set the {@code MBeanExporterListener}s that should be notified + * of MBean registration and unregistration events. + * @see MBeanExporterListener + */ + public void setListeners(MBeanExporterListener... listeners) { + this.listeners = listeners; + } + /** * Set the {@link NotificationListenerBean NotificationListenerBeans} * containing the @@ -333,7 +331,7 @@ public class MBeanExporter extends MBeanRegistrationSupport * @see #setNotificationListenerMappings(java.util.Map) * @see NotificationListenerBean */ - public void setNotificationListeners(NotificationListenerBean[] notificationListeners) { + public void setNotificationListeners(NotificationListenerBean... notificationListeners) { this.notificationListeners = notificationListeners; } @@ -401,17 +399,18 @@ public class MBeanExporter extends MBeanRegistrationSupport //--------------------------------------------------------------------- /** - * Start bean registration automatically when deployed in an + * Kick off 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 - // such as JDK 1.5, Tomcat or JBoss where there is already an MBeanServer loaded. + // where there is already an MBeanServer loaded. if (this.server == null) { this.server = JmxUtils.locateMBeanServer(); } + try { logger.info("Registering beans for JMX exposure on startup"); registerBeans(); @@ -520,7 +519,7 @@ public class MBeanExporter extends MBeanRegistrationSupport } if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) { // Autodetect any beans that are already MBeans. - this.logger.debug("Autodetecting user-defined JMX MBeans"); + logger.debug("Autodetecting user-defined JMX MBeans"); autodetectMBeans(); } // Allow the assembler a chance to vote for bean inclusion. diff --git a/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java b/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java index ab05a3ea6ed..eabd8c0524c 100644 --- a/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/AbstractMBeanServerTests.java @@ -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. @@ -22,6 +22,7 @@ import javax.management.ObjectName; import org.junit.After; import org.junit.Before; + import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.GenericApplicationContext; @@ -51,12 +52,14 @@ public abstract class AbstractMBeanServerTests { protected MBeanServer server; + @Before public final void setUp() throws Exception { this.server = MBeanServerFactory.createMBeanServer(); try { onSetUp(); - } catch (Exception ex) { + } + catch (Exception ex) { releaseServer(); throw ex; } diff --git a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java index c08a9f73b2f..ba123ff9319 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/MBeanExporterTests.java @@ -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. @@ -21,7 +21,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.management.Attribute; import javax.management.InstanceNotFoundException; import javax.management.JMException; @@ -34,6 +33,7 @@ import javax.management.ObjectName; import javax.management.modelmbean.ModelMBeanInfo; import org.junit.Test; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -68,25 +68,10 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor"; - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Test - public void testRegisterNonNotificationListenerType() throws Exception { - Map listeners = new HashMap(); - // 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) { - } - } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testRegisterNullNotificationListenerType() throws Exception { - Map listeners = new HashMap(); + Map listeners = new HashMap(); // put null in as a value... listeners.put("*", null); MBeanExporter exporter = new MBeanExporter(); @@ -98,10 +83,9 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testRegisterNotificationListenerForNonExistentMBean() throws Exception { - Map listeners = new HashMap(); + Map listeners = new HashMap(); NotificationListener dummyListener = new NotificationListener() { @Override public void handleNotification(Notification notification, Object handback) { @@ -175,7 +159,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { assertNotNull(instance); instance = server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean3=true")); assertNotNull(instance); - } finally { + } + finally { bf.destroySingletons(); } } @@ -193,9 +178,11 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { try { server.getObjectInstance(ObjectNameManager.getInstance("spring:mbean=false")); fail("MBean with name spring:mbean=false should have been excluded"); - } catch (InstanceNotFoundException expected) { } - } finally { + catch (InstanceNotFoundException expected) { + } + } + finally { bf.destroySingletons(); } } @@ -217,7 +204,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { assertNotNull(server.getObjectInstance(oname)); name = (String) server.getAttribute(oname, "Name"); assertEquals("Invalid name returned", "Juergen Hoeller", name); - } finally { + } + finally { bf.destroySingletons(); } } @@ -228,7 +216,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { new XmlBeanDefinitionReader(bf).loadBeanDefinitions(new ClassPathResource("autodetectNoMBeans.xml", getClass())); try { bf.getBean("exporter"); - } finally { + } + finally { bf.destroySingletons(); } } @@ -241,7 +230,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { MBeanExporter exporter = new MBeanExporter(); exporter.setBeans(getBeanMap()); exporter.setServer(server); - exporter.setListeners(new MBeanExporterListener[] { listener1, listener2 }); + exporter.setListeners(listener1, listener2); exporter.afterPropertiesSet(); exporter.destroy(); @@ -257,7 +246,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { ProxyFactory factory = new ProxyFactory(); factory.setTarget(bean); factory.addAdvice(new NopInterceptor()); - factory.setInterfaces(new Class[] { IJmxTestBean.class }); + factory.setInterfaces(IJmxTestBean.class); IJmxTestBean proxy = (IJmxTestBean) factory.getProxy(); String name = "bean:mmm=whatever"; @@ -377,8 +366,8 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { 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")); @@ -593,7 +582,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { exporter.setBeans(getBeanMap()); exporter.setServer(this.server); MockMBeanExporterListener listener = new MockMBeanExporterListener(); - exporter.setListeners(new MBeanExporterListener[] { listener }); + exporter.setListeners(listener); exporter.afterPropertiesSet(); assertIsRegistered("The bean was not registered with the MBeanServer", ObjectNameManager.getInstance(OBJECT_NAME)); @@ -702,6 +691,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { assertEquals("Incorrect ObjectName in unregister", desired, listener.getUnregistered().get(0)); } + private static class InvokeDetectAssembler implements MBeanInfoAssembler { private boolean invoked = false; @@ -713,6 +703,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + private static class MockMBeanExporterListener implements MBeanExporterListener { private List registered = new ArrayList(); @@ -738,6 +729,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + private static class SelfNamingTestBean implements SelfNaming { private ObjectName objectName; @@ -752,11 +744,13 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + public static interface PersonMBean { String getName(); } + public static class Person implements PersonMBean { private String name; @@ -771,6 +765,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + public static final class StubNotificationListener implements NotificationListener { private List notifications = new ArrayList(); @@ -785,6 +780,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + private static class RuntimeExceptionThrowingConstructorBean { @SuppressWarnings("unused") @@ -793,6 +789,7 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests { } } + private static final class NamedBeanAutodetectCapableMBeanInfoAssemblerStub extends SimpleReflectiveMBeanInfoAssembler implements AutodetectCapableMBeanInfoAssembler {