Skip to content

Commit 3506779

Browse files
committed
MBeanExporter implements DisposableBean again (also revised logging and rearranged properties)
Issue: SPR-8045
1 parent 46dc07a commit 3506779

File tree

2 files changed

+109
-93
lines changed

2 files changed

+109
-93
lines changed

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

Lines changed: 105 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import java.util.List;
2626
import java.util.Map;
2727
import java.util.Set;
28-
2928
import javax.management.DynamicMBean;
3029
import javax.management.JMException;
3130
import javax.management.MBeanException;
@@ -46,6 +45,7 @@
4645
import org.springframework.beans.factory.BeanFactory;
4746
import org.springframework.beans.factory.BeanFactoryAware;
4847
import org.springframework.beans.factory.CannotLoadBeanClassException;
48+
import org.springframework.beans.factory.DisposableBean;
4949
import org.springframework.beans.factory.InitializingBean;
5050
import org.springframework.beans.factory.ListableBeanFactory;
5151
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -82,8 +82,7 @@
8282
* via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing
8383
* application code to be notified of MBean registration and unregistration events.
8484
*
85-
* <p>This exporter is compatible with JMX 1.2 on Java 5 and above.
86-
* As of Spring 2.5, it also autodetects and exports Java 6 MXBeans.
85+
* <p>This exporter is compatible with MBeans and MXBeans on Java 6 and above.
8786
*
8887
* @author Rob Harrop
8988
* @author Juergen Hoeller
@@ -99,8 +98,8 @@
9998
* @see org.springframework.jmx.export.assembler.MBeanInfoAssembler
10099
* @see MBeanExporterListener
101100
*/
102-
public class MBeanExporter extends MBeanRegistrationSupport
103-
implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, SmartLifecycle {
101+
public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExportOperations,
102+
BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean, SmartLifecycle {
104103

105104
/**
106105
* Autodetection mode indicating that no autodetection should be used.
@@ -149,11 +148,11 @@ public class MBeanExporter extends MBeanRegistrationSupport
149148
/** Whether to eagerly initialize candidate beans when autodetecting MBeans */
150149
private boolean allowEagerInit = false;
151150

152-
/** Indicates whether Spring should modify generated ObjectNames */
153-
private boolean ensureUniqueRuntimeObjectNames = true;
151+
/** Stores the MBeanInfoAssembler to use for this exporter */
152+
private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();
154153

155-
/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
156-
private boolean exposeManagedResourceClassLoader = true;
154+
/** The strategy to use for creating ObjectNames for an object */
155+
private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();
157156

158157
/** A set of bean names that should be excluded from autodetection */
159158
private Set<String> excludedBeans;
@@ -168,23 +167,25 @@ public class MBeanExporter extends MBeanRegistrationSupport
168167
private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners =
169168
new LinkedHashMap<NotificationListenerBean, ObjectName[]>();
170169

171-
/** Stores the MBeanInfoAssembler to use for this exporter */
172-
private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();
170+
/** Indicates whether Spring should modify generated ObjectNames */
171+
private boolean ensureUniqueRuntimeObjectNames = true;
173172

174-
/** The strategy to use for creating ObjectNames for an object */
175-
private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();
173+
/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
174+
private boolean exposeManagedResourceClassLoader = true;
175+
176+
/** Indicate whether to auto-startup within the container-managed lifecycle */
177+
private boolean autoStartup = true;
178+
179+
/** Indicate the phase to use within the container-managed lifecycle */
180+
private int phase = Integer.MAX_VALUE;
176181

177182
/** Stores the ClassLoader to use for generating lazy-init proxies */
178183
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
179184

180185
/** Stores the BeanFactory for use in autodetection process */
181186
private ListableBeanFactory beanFactory;
182187

183-
private boolean autoStartup = true;
184-
185-
private volatile boolean running = false;
186-
187-
private int phase = Integer.MAX_VALUE;
188+
private boolean running = false;
188189

189190
private final Object lifecycleMonitor = new Object();
190191

@@ -294,45 +295,20 @@ public void setNamingStrategy(ObjectNamingStrategy namingStrategy) {
294295
this.namingStrategy = namingStrategy;
295296
}
296297

297-
/**
298-
* Set the {@code MBeanExporterListener}s that should be notified
299-
* of MBean registration and unregistration events.
300-
* @see MBeanExporterListener
301-
*/
302-
public void setListeners(MBeanExporterListener[] listeners) {
303-
this.listeners = listeners;
304-
}
305-
306298
/**
307299
* Set the list of names for beans that should be excluded from autodetection.
308300
*/
309-
public void setExcludedBeans(String[] excludedBeans) {
301+
public void setExcludedBeans(String... excludedBeans) {
310302
this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null);
311303
}
312304

313305
/**
314-
* Indicates whether Spring should ensure that {@link ObjectName ObjectNames}
315-
* generated by the configured {@link ObjectNamingStrategy} for
316-
* runtime-registered MBeans ({@link #registerManagedResource}) should get
317-
* modified: to ensure uniqueness for every instance of a managed {@code Class}.
318-
* <p>The default value is {@code true}.
319-
* @see #registerManagedResource
320-
* @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
321-
*/
322-
public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
323-
this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
324-
}
325-
326-
/**
327-
* Indicates whether or not the managed resource should be exposed on the
328-
* {@link Thread#getContextClassLoader() thread context ClassLoader} before
329-
* allowing any invocations on the MBean to occur.
330-
* <p>The default value is {@code true}, exposing a {@link SpringModelMBean}
331-
* which performs thread context ClassLoader management. Switch this flag off to
332-
* expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
306+
* Set the {@code MBeanExporterListener}s that should be notified
307+
* of MBean registration and unregistration events.
308+
* @see MBeanExporterListener
333309
*/
334-
public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
335-
this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
310+
public void setListeners(MBeanExporterListener... listeners) {
311+
this.listeners = listeners;
336312
}
337313

338314
/**
@@ -343,7 +319,7 @@ public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceCla
343319
* @see #setNotificationListenerMappings(java.util.Map)
344320
* @see NotificationListenerBean
345321
*/
346-
public void setNotificationListeners(NotificationListenerBean[] notificationListeners) {
322+
public void setNotificationListeners(NotificationListenerBean... notificationListeners) {
347323
this.notificationListeners = notificationListeners;
348324
}
349325

@@ -382,6 +358,61 @@ public void setNotificationListenerMappings(Map<?, ? extends NotificationListene
382358
notificationListeners.toArray(new NotificationListenerBean[notificationListeners.size()]);
383359
}
384360

361+
/**
362+
* Indicates whether Spring should ensure that {@link ObjectName ObjectNames}
363+
* generated by the configured {@link ObjectNamingStrategy} for
364+
* runtime-registered MBeans ({@link #registerManagedResource}) should get
365+
* modified: to ensure uniqueness for every instance of a managed {@code Class}.
366+
* <p>The default value is {@code true}.
367+
* @see #registerManagedResource
368+
* @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
369+
*/
370+
public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
371+
this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
372+
}
373+
374+
/**
375+
* Indicates whether or not the managed resource should be exposed on the
376+
* {@link Thread#getContextClassLoader() thread context ClassLoader} before
377+
* allowing any invocations on the MBean to occur.
378+
* <p>The default value is {@code true}, exposing a {@link SpringModelMBean}
379+
* which performs thread context ClassLoader management. Switch this flag off to
380+
* expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
381+
*/
382+
public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
383+
this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
384+
}
385+
386+
/**
387+
* Set whether to automatically export MBeans after initialization.
388+
* <p>Default is "true"; set this to "false" to allow for manual startup
389+
* through the {@link #start()} method.
390+
*/
391+
public void setAutoStartup(boolean autoStartup) {
392+
this.autoStartup = autoStartup;
393+
}
394+
395+
@Override
396+
public boolean isAutoStartup() {
397+
return this.autoStartup;
398+
}
399+
400+
/**
401+
* Specify the phase in which the MBeans should be exported to the
402+
* JMX domain. The startup order proceeds from lowest to highest, and
403+
* the shutdown order is the reverse of that. By default this value
404+
* is {@code Integer.MAX_VALUE} meaning that MBeans are exported
405+
* as late as possible and removed from the domain as soon as possible.
406+
*/
407+
public void setPhase(int phase) {
408+
this.phase = phase;
409+
}
410+
411+
@Override
412+
public int getPhase() {
413+
return this.phase;
414+
}
415+
385416
@Override
386417
public void setBeanClassLoader(ClassLoader classLoader) {
387418
this.beanClassLoader = classLoader;
@@ -405,71 +436,47 @@ public void setBeanFactory(BeanFactory beanFactory) {
405436
}
406437
}
407438

408-
/**
409-
* Specify the phase in which the MBeans should be exported to the
410-
* JMX domain. The startup order proceeds from lowest to highest, and
411-
* the shutdown order is the reverse of that. By default this value
412-
* is {@code Integer.MAX_VALUE} meaning that MBeans are exported
413-
* as late as possible and removed from the domain as soon as possible.
414-
*/
415-
public void setPhase(int phase) {
416-
this.phase = phase;
417-
}
418-
419-
/**
420-
* Set whether to automatically export MBeans after initialization.
421-
* <p>Default is "true"; set this to "false" to allow for manual startup
422-
* through the {@link #start()} method.
423-
*/
424-
public void setAutoStartup(boolean autoStartup) {
425-
this.autoStartup = autoStartup;
426-
}
427-
428-
429-
//---------------------------------------------------------------------
430-
// Lifecycle in bean factory: automatically register/unregister beans
431-
//---------------------------------------------------------------------
432-
433439
@Override
434440
public void afterPropertiesSet() {
435441
// If no server was provided then try to find one. This is useful in an environment
436-
// such as JDK 1.5, Tomcat or JBoss where there is already an MBeanServer loaded.
442+
// where there is already an MBeanServer loaded.
437443
if (this.server == null) {
438444
this.server = JmxUtils.locateMBeanServer();
439445
}
440446
}
441447

448+
449+
//---------------------------------------------------------------------
450+
// Implementation of SmartLifecycle interface
451+
//---------------------------------------------------------------------
452+
442453
@Override
443454
public void start() {
444-
logger.info("Registering beans for JMX exposure");
445455
synchronized (this.lifecycleMonitor) {
446456
try {
447457
registerBeans();
448458
registerNotificationListeners();
449-
} catch (RuntimeException ex) {
459+
}
460+
catch (RuntimeException ex) {
450461
// Unregister beans already registered by this exporter.
451-
unregisterNotificationListeners();
452-
unregisterBeans();
462+
doStop();
453463
throw ex;
454464
}
465+
this.running = true;
455466
}
456-
running = true;
457467
}
458468

459469
@Override
460470
public void stop() {
461-
logger.info("Unregistering JMX-exposed beans on stop");
462471
synchronized (this.lifecycleMonitor) {
463-
unregisterNotificationListeners();
464-
unregisterBeans();
465-
running = false;
472+
doStop();
466473
}
467474
}
468475

469476
@Override
470477
public void stop(Runnable callback) {
471478
synchronized (this.lifecycleMonitor) {
472-
stop();
479+
doStop();
473480
callback.run();
474481
}
475482
}
@@ -482,13 +489,16 @@ public boolean isRunning() {
482489
}
483490

484491
@Override
485-
public boolean isAutoStartup() {
486-
return this.autoStartup;
492+
public void destroy() {
493+
synchronized (this.lifecycleMonitor) {
494+
doStop();
495+
}
487496
}
488497

489-
@Override
490-
public int getPhase() {
491-
return this.phase;
498+
private void doStop() {
499+
unregisterNotificationListeners();
500+
unregisterBeans();
501+
this.running = false;
492502
}
493503

494504

@@ -558,6 +568,8 @@ public void unregisterManagedResource(ObjectName objectName) {
558568
* implementation of the {@code ObjectNamingStrategy} interface being used.
559569
*/
560570
protected void registerBeans() {
571+
logger.info("Registering beans for JMX exposure");
572+
561573
// The beans property may be null, for example if we are relying solely on autodetection.
562574
if (this.beans == null) {
563575
this.beans = new HashMap<String, Object>();
@@ -575,7 +587,7 @@ protected void registerBeans() {
575587
}
576588
if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
577589
// Autodetect any beans that are already MBeans.
578-
this.logger.debug("Autodetecting user-defined JMX MBeans");
590+
logger.info("Autodetecting user-defined JMX MBeans");
579591
autodetectMBeans();
580592
}
581593
// Allow the assembler a chance to vote for bean inclusion.
@@ -1109,6 +1121,7 @@ private void notifyListenersOfUnregistration(ObjectName objectName) {
11091121
}
11101122
}
11111123

1124+
11121125
//---------------------------------------------------------------------
11131126
// Inner classes for internal use
11141127
//---------------------------------------------------------------------

spring-context/src/main/java/org/springframework/jmx/support/MBeanRegistrationSupport.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -237,6 +237,9 @@ protected void unregisterBeans() {
237237
synchronized (this.registeredBeans) {
238238
snapshot = new LinkedHashSet<ObjectName>(this.registeredBeans);
239239
}
240+
if (!snapshot.isEmpty()) {
241+
logger.info("Unregistering JMX-exposed beans");
242+
}
240243
for (ObjectName objectName : snapshot) {
241244
doUnregister(objectName);
242245
}

0 commit comments

Comments
 (0)