2525import  java .util .List ;
2626import  java .util .Map ;
2727import  java .util .Set ;
28- 
2928import  javax .management .DynamicMBean ;
3029import  javax .management .JMException ;
3130import  javax .management .MBeanException ;
4645import  org .springframework .beans .factory .BeanFactory ;
4746import  org .springframework .beans .factory .BeanFactoryAware ;
4847import  org .springframework .beans .factory .CannotLoadBeanClassException ;
48+ import  org .springframework .beans .factory .DisposableBean ;
4949import  org .springframework .beans .factory .InitializingBean ;
5050import  org .springframework .beans .factory .ListableBeanFactory ;
5151import  org .springframework .beans .factory .config .ConfigurableBeanFactory ;
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 
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	//--------------------------------------------------------------------- 
0 commit comments