MBeanExporter implements DisposableBean again (also revised logging and rearranged properties)

Issue: SPR-8045
This commit is contained in:
Juergen Hoeller 2014-06-26 15:55:40 +02:00
parent 46dc07a005
commit 35067790f3
2 changed files with 109 additions and 93 deletions

View File

@ -25,7 +25,6 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.management.DynamicMBean; import javax.management.DynamicMBean;
import javax.management.JMException; import javax.management.JMException;
import javax.management.MBeanException; import javax.management.MBeanException;
@ -46,6 +45,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.CannotLoadBeanClassException; import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@ -82,8 +82,7 @@ import org.springframework.util.ObjectUtils;
* via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing * via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing
* application code to be notified of MBean registration and unregistration events. * application code to be notified of MBean registration and unregistration events.
* *
* <p>This exporter is compatible with JMX 1.2 on Java 5 and above. * <p>This exporter is compatible with MBeans and MXBeans on Java 6 and above.
* As of Spring 2.5, it also autodetects and exports Java 6 MXBeans.
* *
* @author Rob Harrop * @author Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
@ -99,8 +98,8 @@ import org.springframework.util.ObjectUtils;
* @see org.springframework.jmx.export.assembler.MBeanInfoAssembler * @see org.springframework.jmx.export.assembler.MBeanInfoAssembler
* @see MBeanExporterListener * @see MBeanExporterListener
*/ */
public class MBeanExporter extends MBeanRegistrationSupport public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExportOperations,
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, SmartLifecycle { BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean, SmartLifecycle {
/** /**
* Autodetection mode indicating that no autodetection should be used. * Autodetection mode indicating that no autodetection should be used.
@ -149,11 +148,11 @@ public class MBeanExporter extends MBeanRegistrationSupport
/** Whether to eagerly initialize candidate beans when autodetecting MBeans */ /** Whether to eagerly initialize candidate beans when autodetecting MBeans */
private boolean allowEagerInit = false; private boolean allowEagerInit = false;
/** Indicates whether Spring should modify generated ObjectNames */ /** Stores the MBeanInfoAssembler to use for this exporter */
private boolean ensureUniqueRuntimeObjectNames = true; private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();
/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */ /** The strategy to use for creating ObjectNames for an object */
private boolean exposeManagedResourceClassLoader = true; private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();
/** A set of bean names that should be excluded from autodetection */ /** A set of bean names that should be excluded from autodetection */
private Set<String> excludedBeans; private Set<String> excludedBeans;
@ -168,11 +167,17 @@ public class MBeanExporter extends MBeanRegistrationSupport
private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners = private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners =
new LinkedHashMap<NotificationListenerBean, ObjectName[]>(); new LinkedHashMap<NotificationListenerBean, ObjectName[]>();
/** Stores the MBeanInfoAssembler to use for this exporter */ /** Indicates whether Spring should modify generated ObjectNames */
private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler(); private boolean ensureUniqueRuntimeObjectNames = true;
/** The strategy to use for creating ObjectNames for an object */ /** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy(); private boolean exposeManagedResourceClassLoader = true;
/** Indicate whether to auto-startup within the container-managed lifecycle */
private boolean autoStartup = true;
/** Indicate the phase to use within the container-managed lifecycle */
private int phase = Integer.MAX_VALUE;
/** Stores the ClassLoader to use for generating lazy-init proxies */ /** Stores the ClassLoader to use for generating lazy-init proxies */
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@ -180,11 +185,7 @@ public class MBeanExporter extends MBeanRegistrationSupport
/** Stores the BeanFactory for use in autodetection process */ /** Stores the BeanFactory for use in autodetection process */
private ListableBeanFactory beanFactory; private ListableBeanFactory beanFactory;
private boolean autoStartup = true; private boolean running = false;
private volatile boolean running = false;
private int phase = Integer.MAX_VALUE;
private final Object lifecycleMonitor = new Object(); private final Object lifecycleMonitor = new Object();
@ -294,45 +295,20 @@ public class MBeanExporter extends MBeanRegistrationSupport
this.namingStrategy = namingStrategy; 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. * Set the list of names for beans that should be excluded from autodetection.
*/ */
public void setExcludedBeans(String[] excludedBeans) { public void setExcludedBeans(String... excludedBeans) {
this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null); this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null);
} }
/** /**
* Indicates whether Spring should ensure that {@link ObjectName ObjectNames} * Set the {@code MBeanExporterListener}s that should be notified
* generated by the configured {@link ObjectNamingStrategy} for * of MBean registration and unregistration events.
* runtime-registered MBeans ({@link #registerManagedResource}) should get * @see MBeanExporterListener
* modified: to ensure uniqueness for every instance of a managed {@code Class}.
* <p>The default value is {@code true}.
* @see #registerManagedResource
* @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
*/ */
public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) { public void setListeners(MBeanExporterListener... listeners) {
this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames; this.listeners = listeners;
}
/**
* Indicates whether or not the managed resource should be exposed on the
* {@link Thread#getContextClassLoader() thread context ClassLoader} before
* allowing any invocations on the MBean to occur.
* <p>The default value is {@code true}, exposing a {@link SpringModelMBean}
* which performs thread context ClassLoader management. Switch this flag off to
* expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
*/
public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
} }
/** /**
@ -343,7 +319,7 @@ public class MBeanExporter extends MBeanRegistrationSupport
* @see #setNotificationListenerMappings(java.util.Map) * @see #setNotificationListenerMappings(java.util.Map)
* @see NotificationListenerBean * @see NotificationListenerBean
*/ */
public void setNotificationListeners(NotificationListenerBean[] notificationListeners) { public void setNotificationListeners(NotificationListenerBean... notificationListeners) {
this.notificationListeners = notificationListeners; this.notificationListeners = notificationListeners;
} }
@ -382,6 +358,61 @@ public class MBeanExporter extends MBeanRegistrationSupport
notificationListeners.toArray(new NotificationListenerBean[notificationListeners.size()]); notificationListeners.toArray(new NotificationListenerBean[notificationListeners.size()]);
} }
/**
* Indicates whether Spring should ensure that {@link ObjectName ObjectNames}
* generated by the configured {@link ObjectNamingStrategy} for
* runtime-registered MBeans ({@link #registerManagedResource}) should get
* modified: to ensure uniqueness for every instance of a managed {@code Class}.
* <p>The default value is {@code true}.
* @see #registerManagedResource
* @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
*/
public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
}
/**
* Indicates whether or not the managed resource should be exposed on the
* {@link Thread#getContextClassLoader() thread context ClassLoader} before
* allowing any invocations on the MBean to occur.
* <p>The default value is {@code true}, exposing a {@link SpringModelMBean}
* which performs thread context ClassLoader management. Switch this flag off to
* expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
*/
public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
}
/**
* 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;
}
@Override
public boolean isAutoStartup() {
return this.autoStartup;
}
/**
* 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;
}
@Override
public int getPhase() {
return this.phase;
}
@Override @Override
public void setBeanClassLoader(ClassLoader classLoader) { public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader; this.beanClassLoader = classLoader;
@ -405,71 +436,47 @@ 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
//---------------------------------------------------------------------
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
// If no server was provided then try to find one. This is useful in an environment // 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) { if (this.server == null) {
this.server = JmxUtils.locateMBeanServer(); this.server = JmxUtils.locateMBeanServer();
} }
} }
//---------------------------------------------------------------------
// Implementation of SmartLifecycle interface
//---------------------------------------------------------------------
@Override @Override
public void start() { public void start() {
logger.info("Registering beans for JMX exposure");
synchronized (this.lifecycleMonitor) { synchronized (this.lifecycleMonitor) {
try { try {
registerBeans(); registerBeans();
registerNotificationListeners(); registerNotificationListeners();
} catch (RuntimeException ex) { }
catch (RuntimeException ex) {
// Unregister beans already registered by this exporter. // Unregister beans already registered by this exporter.
unregisterNotificationListeners(); doStop();
unregisterBeans();
throw ex; throw ex;
} }
this.running = true;
} }
running = true;
} }
@Override @Override
public void stop() { public void stop() {
logger.info("Unregistering JMX-exposed beans on stop");
synchronized (this.lifecycleMonitor) { synchronized (this.lifecycleMonitor) {
unregisterNotificationListeners(); doStop();
unregisterBeans();
running = false;
} }
} }
@Override @Override
public void stop(Runnable callback) { public void stop(Runnable callback) {
synchronized (this.lifecycleMonitor) { synchronized (this.lifecycleMonitor) {
stop(); doStop();
callback.run(); callback.run();
} }
} }
@ -482,13 +489,16 @@ public class MBeanExporter extends MBeanRegistrationSupport
} }
@Override @Override
public boolean isAutoStartup() { public void destroy() {
return this.autoStartup; synchronized (this.lifecycleMonitor) {
doStop();
}
} }
@Override private void doStop() {
public int getPhase() { unregisterNotificationListeners();
return this.phase; unregisterBeans();
this.running = false;
} }
@ -558,6 +568,8 @@ public class MBeanExporter extends MBeanRegistrationSupport
* implementation of the {@code ObjectNamingStrategy} interface being used. * implementation of the {@code ObjectNamingStrategy} interface being used.
*/ */
protected void registerBeans() { protected void registerBeans() {
logger.info("Registering beans for JMX exposure");
// The beans property may be null, for example if we are relying solely on autodetection. // The beans property may be null, for example if we are relying solely on autodetection.
if (this.beans == null) { if (this.beans == null) {
this.beans = new HashMap<String, Object>(); this.beans = new HashMap<String, Object>();
@ -575,7 +587,7 @@ public class MBeanExporter extends MBeanRegistrationSupport
} }
if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) { if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
// Autodetect any beans that are already MBeans. // Autodetect any beans that are already MBeans.
this.logger.debug("Autodetecting user-defined JMX MBeans"); logger.info("Autodetecting user-defined JMX MBeans");
autodetectMBeans(); autodetectMBeans();
} }
// Allow the assembler a chance to vote for bean inclusion. // Allow the assembler a chance to vote for bean inclusion.
@ -1109,6 +1121,7 @@ public class MBeanExporter extends MBeanRegistrationSupport
} }
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Inner classes for internal use // Inner classes for internal use
//--------------------------------------------------------------------- //---------------------------------------------------------------------

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -237,6 +237,9 @@ public class MBeanRegistrationSupport {
synchronized (this.registeredBeans) { synchronized (this.registeredBeans) {
snapshot = new LinkedHashSet<ObjectName>(this.registeredBeans); snapshot = new LinkedHashSet<ObjectName>(this.registeredBeans);
} }
if (!snapshot.isEmpty()) {
logger.info("Unregistering JMX-exposed beans");
}
for (ObjectName objectName : snapshot) { for (ObjectName objectName : snapshot) {
doUnregister(objectName); doUnregister(objectName);
} }