MBeanExporter should not implement SmartLifecycle but rather receive a ContextRefreshedEvent-like callback

This commit removes the immediate package dependency cycle between the context and jmx packages. A specific callback arrangement will follow in time for 4.1 RC1; at this point, it's temporarily back to registration kicked off by afterPropertiesSet again.

Issue: SPR-8045
This commit is contained in:
Juergen Hoeller
2014-07-07 21:45:40 +02:00
parent b559f15a00
commit 1115374188
4 changed files with 89 additions and 199 deletions

View File

@@ -50,7 +50,6 @@ 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;
@@ -99,7 +98,7 @@ import org.springframework.util.ObjectUtils;
* @see MBeanExporterListener
*/
public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExportOperations,
BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean, SmartLifecycle {
BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
/**
* Autodetection mode indicating that no autodetection should be used.
@@ -154,6 +153,12 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
/** 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;
/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
private boolean exposeManagedResourceClassLoader = true;
/** A set of bean names that should be excluded from autodetection */
private Set<String> excludedBeans;
@@ -167,28 +172,12 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners =
new LinkedHashMap<NotificationListenerBean, ObjectName[]>();
/** Indicates whether Spring should modify generated ObjectNames */
private boolean ensureUniqueRuntimeObjectNames = true;
/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
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 */
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/** Stores the BeanFactory for use in autodetection process */
private ListableBeanFactory beanFactory;
private boolean running = false;
private final Object lifecycleMonitor = new Object();
/**
* Supply a {@code Map} of beans to be registered with the JMX
@@ -295,6 +284,31 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
this.namingStrategy = namingStrategy;
}
/**
* 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 the list of names for beans that should be excluded from autodetection.
*/
@@ -358,61 +372,6 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
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
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
@@ -436,6 +395,11 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
}
}
//---------------------------------------------------------------------
// Lifecycle in bean factory: automatically register/unregister beans
//---------------------------------------------------------------------
@Override
public void afterPropertiesSet() {
// If no server was provided then try to find one. This is useful in an environment
@@ -443,62 +407,36 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
if (this.server == null) {
this.server = JmxUtils.locateMBeanServer();
}
register(); // TODO: to be replaced with some ContextRefreshedEvent-like callback
}
//---------------------------------------------------------------------
// Implementation of SmartLifecycle interface
//---------------------------------------------------------------------
@Override
public void start() {
synchronized (this.lifecycleMonitor) {
try {
registerBeans();
registerNotificationListeners();
}
catch (RuntimeException ex) {
// Unregister beans already registered by this exporter.
doStop();
throw ex;
}
this.running = true;
}
}
@Override
public void stop() {
synchronized (this.lifecycleMonitor) {
doStop();
}
}
@Override
public void stop(Runnable callback) {
synchronized (this.lifecycleMonitor) {
doStop();
callback.run();
}
}
@Override
public boolean isRunning() {
synchronized (this.lifecycleMonitor) {
return this.running;
/**
* Kick off bean registration automatically when deployed in an {@code ApplicationContext}.
* @see #registerBeans()
*/
public void register() {
try {
logger.info("Registering beans for JMX exposure on startup");
registerBeans();
registerNotificationListeners();
}
catch (RuntimeException ex) {
// Unregister beans already registered by this exporter.
unregisterNotificationListeners();
unregisterBeans();
throw ex;
}
}
/**
* Unregisters all beans that this exported has exposed via JMX
* when the enclosing {@code ApplicationContext} is destroyed.
*/
@Override
public void destroy() {
synchronized (this.lifecycleMonitor) {
doStop();
}
}
private void doStop() {
logger.info("Unregistering JMX-exposed beans on shutdown");
unregisterNotificationListeners();
unregisterBeans();
this.running = false;
}
@@ -568,8 +506,6 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* implementation of the {@code ObjectNamingStrategy} interface being used.
*/
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.
if (this.beans == null) {
this.beans = new HashMap<String, Object>();
@@ -587,7 +523,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
}
if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
// Autodetect any beans that are already MBeans.
logger.info("Autodetecting user-defined JMX MBeans");
logger.debug("Autodetecting user-defined JMX MBeans");
autodetectMBeans();
}
// Allow the assembler a chance to vote for bean inclusion.