MBean Exportソース分析

33992 ワード


/**
 * JMX          Spring  Bean  JMX,          JMX  
 *     bean       JMX     ,MBeanExporter                 MBeanServer  
 *
 *     bean       JMX     ,MBeanExporter      MBeanInfoAssembler        
 * 
 */
public class MBeanExporter extends MBeanRegistrationSupport
		implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {

	/**
	 *      
	 */
	public static final int AUTODETECT_NONE = 0;

	/**
	 *        MBean
	 */
	public static final int AUTODETECT_MBEAN = 1;

	/**
	 *     MBeanInfoAssember
	 */
	public static final int AUTODETECT_ASSEMBLER = 2;

	/**
	 *      
	 */
	public static final int AUTODETECT_ALL = AUTODETECT_MBEAN | AUTODETECT_ASSEMBLER;


	/**
	 *    
	 */
	private static final String WILDCARD = "*";

	/** Constant for the JMX <code>mr_type</code> "ObjectReference" */
	private static final String MR_TYPE_OBJECT_REFERENCE = "ObjectReference";

	/** Prefix for the autodetect constants defined in this class */
	private static final String CONSTANT_PREFIX_AUTODETECT = "AUTODETECT_";


	/**     COnstants   */
	private static final Constants constants = new Constants(MBeanExporter.class);

	/**      JMX     bean,   JMX      **/
	private Map<String, Object> beans;

	/**        */
	private Integer autodetectMode;

	/**        MBean ,       bean**/
	private boolean allowEagerInit = false;

	/**   Spring       ObjectName */
	private boolean ensureUniqueRuntimeObjectNames = true;

	/**   Spring   MBean       **/ 
	private boolean exposeManagedResourceClassLoader = true;

	/**           bean */
	private Set<String> excludedBeans;

	/** MBeanExporter     */
	private MBeanExporterListener[] listeners;

	/**    */
	private NotificationListenerBean[] notificationListeners;

	private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners =
			new LinkedHashMap<NotificationListenerBean, ObjectName[]>();

	/**         MBeanInfo   ,       MBeanInfo   ***/ 
	private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();

	/**        ObjectName   */
	private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();

	/**            ClassLoader**/
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/**        BeanFactory */
	private ListableBeanFactory beanFactory;


	/**
	 *          JMX MBeanServer bean    ,   key   JMX        。
	 *      ,  JMX  ObjectName        key   。        NamingStragegy     
	 */
	public void setBeans(Map<String, Object> beans) {
		this.beans = beans;
	}

	/**
	 *        
	 */
	public void setAutodetect(boolean autodetect) {
		this.autodetectMode = (autodetect ? AUTODETECT_ALL : AUTODETECT_NONE);
	}

	/**
	 *         
	 */
	public void setAutodetectMode(int autodetectMode) {
		if (!constants.getValues(CONSTANT_PREFIX_AUTODETECT).contains(autodetectMode)) {
			throw new IllegalArgumentException("Only values of autodetect constants allowed");
		}
		this.autodetectMode = autodetectMode;
	}

	
	public void setAutodetectModeName(String constantName) {
		if (constantName == null || !constantName.startsWith(CONSTANT_PREFIX_AUTODETECT)) {
			throw new IllegalArgumentException("Only autodetect constants allowed");
		}
		this.autodetectMode = (Integer) constants.asNumber(constantName);
	}

	
	public void setAllowEagerInit(boolean allowEagerInit) {
		this.allowEagerInit = allowEagerInit;
	}

	/**
	 *   MBeanInfo   
	 **/
	public void setAssembler(MBeanInfoAssembler assembler) {
		this.assembler = assembler;
	}

	public void setNamingStrategy(ObjectNamingStrategy namingStrategy) {
		this.namingStrategy = namingStrategy;
	}

	public void setListeners(MBeanExporterListener[] listeners) {
		this.listeners = listeners;
	}

	
	public void setExcludedBeans(String[] excludedBeans) {
		this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null);
	}

	
	public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
		this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
	}

	
	public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
		this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
	}

	
	public void setNotificationListeners(NotificationListenerBean[] notificationListeners) {
		this.notificationListeners = notificationListeners;
	}

	/**
	 *       
	 */
	public void setNotificationListenerMappings(Map<?, ? extends NotificationListener> listeners) {
		Assert.notNull(listeners, "'listeners' must not be null");
		List<NotificationListenerBean> notificationListeners =
				new ArrayList<NotificationListenerBean>(listeners.size());

		for (Map.Entry<?, ? extends NotificationListener> entry : listeners.entrySet()) {
			//  map      ,     Spring NotificationListenerBean
			NotificationListenerBean bean = new NotificationListenerBean(entry.getValue());
			//   ObjectName
			Object key = entry.getKey();
			//   key  null      
			if (key != null && !WILDCARD.equals(key)) {
				//              ObjectName
				bean.setMappedObjectName(entry.getKey());
			}
			//      
			notificationListeners.add(bean);
		}

		this.notificationListeners =
				notificationListeners.toArray(new NotificationListenerBean[notificationListeners.size()]);
	}

	public void setBeanClassLoader(ClassLoader classLoader) {
		this.beanClassLoader = classLoader;
	}

	public void setBeanFactory(BeanFactory beanFactory) {
		if (beanFactory instanceof ListableBeanFactory) {
			this.beanFactory = (ListableBeanFactory) beanFactory;
		}
		else {
			logger.info("MBeanExporter not running in a ListableBeanFactory: autodetection of MBeans not available.");
		}
	}


	//---------------------------------------------------------------------
	// Lifecycle in bean factory: automatically register/unregister beans
	//---------------------------------------------------------------------

	/**
	 *               
	 */
	public void afterPropertiesSet() {
		// //    MBeanServer   ,        MBeanServer.   JDK1.5,Tomcat  JBoss        MBeanServer//        
		if (this.server == null) {
			this.server = JmxUtils.locateMBeanServer();
		}
		try {
			logger.info("Registering beans for JMX exposure on startup");
			//  MBean
			registerBeans();
			//       
			registerNotificationListeners();
		}
		catch (RuntimeException ex) {
			//       
			unregisterNotificationListeners();
			//  MBean
			unregisterBeans();
			throw ex;
		}
	}

	/**
	 *   
	 */
	public void destroy() {
		logger.info("Unregistering JMX-exposed beans on shutdown");
		unregisterNotificationListeners();
		unregisterBeans();
	}


	//---------------------------------------------------------------------
	// Implementation of MBeanExportOperations interface
	//---------------------------------------------------------------------

	public ObjectName registerManagedResource(Object managedResource) throws MBeanExportException {
		Assert.notNull(managedResource, "Managed resource must not be null");
		ObjectName objectName;
		try {
			objectName = getObjectName(managedResource, null);
			if (this.ensureUniqueRuntimeObjectNames) {
				objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
			}
		}
		catch (Exception ex) {
			throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
		}
		registerManagedResource(managedResource, objectName);
		return objectName;
	}

	public void registerManagedResource(Object managedResource, ObjectName objectName) throws MBeanExportException {
		Assert.notNull(managedResource, "Managed resource must not be null");
		Assert.notNull(objectName, "ObjectName must not be null");
		try {
			if (isMBean(managedResource.getClass())) {
				doRegister(managedResource, objectName);
			}
			else {
				ModelMBean mbean = createAndConfigureMBean(managedResource, managedResource.getClass().getName());
				doRegister(mbean, objectName);
				injectNotificationPublisherIfNecessary(managedResource, mbean, objectName);
			}
		}
		catch (JMException ex) {
			throw new UnableToRegisterMBeanException(
					"Unable to register MBean [" + managedResource + "] with object name [" + objectName + "]", ex);
		}
	}

	public void unregisterManagedResource(ObjectName objectName) {
		Assert.notNull(objectName, "ObjectName must not be null");
		doUnregister(objectName);
	}


	//---------------------------------------------------------------------
	// Exporter implementation
	//---------------------------------------------------------------------

	/**
	 *   MBeanServer       Bean
	 *    Bean    ModelMBean   MBeanServer
	 *   ModelMBean             ModelMBeanProvider     。
	 *      ,RequiredModelMBean      JMX   
	 *
	 * <p>The management interface produced for each bean is dependent on the
	 * <code>MBeanInfoAssembler</code> implementation being used. The
	 * <code>ObjectName</code> given to each bean is dependent on the
	 * implementation of the <code>ObjectNamingStrategy</code> interface being used.
	 */
	protected void registerBeans() {
		//   beans null
		if (this.beans == null) {
			this.beans = new HashMap<String, Object>();
			//         autodetectMode ,    AUTODETECT_ALL
			if (this.autodetectMode == null) {
				this.autodetectMode = AUTODETECT_ALL;
			}
		}

		//   autodetectMode  null,   autodetectModel    AUTODETECT_NONE
		int mode = (this.autodetectMode != null ? this.autodetectMode : AUTODETECT_NONE);
		//     AUTODETECT_NONE
		if (mode != AUTODETECT_NONE) {
			//   beanFactory==null,       
			if (this.beanFactory == null) {
				throw new MBeanExportException("Cannot autodetect MBeans if not running in a BeanFactory");
			}
			//     AUTODETECT_MBEAN   AUTODETECT_ALL,     MBean
			if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
				// Autodetect any beans that are already MBeans.
				this.logger.debug("Autodetecting user-defined JMX MBeans");
				autodetectMBeans();
			}
			// Allow the assembler a chance to vote for bean inclusion.
			if ((mode == AUTODETECT_ASSEMBLER || mode == AUTODETECT_ALL) &&
					this.assembler instanceof AutodetectCapableMBeanInfoAssembler) {
				autodetectBeans((AutodetectCapableMBeanInfoAssembler) this.assembler);
			}
		}
	//   beans   
		if (!this.beans.isEmpty()) {
		//   beans
			for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
				//  bean
				registerBeanNameOrInstance(entry.getValue(), entry.getKey());
			}
		}
	}

	/**
	 *     bean        bean
	 */
	protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, String beanName) {
		return (beanFactory instanceof ConfigurableListableBeanFactory && beanFactory.containsBeanDefinition(beanName) &&
				((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName).isLazyInit());
	}

	/**
	 *   MBeanServer    Bean。 
	 *                   MBeanServer.    ,     mapValue      Bean   
	 * *   MBeanServer         ,            。    Bean     Mbean,        ,  **   MBeanServer  。    Bean Bean   ,  MBeaServer      
	 */
	protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException {
		try {
		     //   mapValue    
			if (mapValue instanceof String) {
				// beanFactory null       
				if (this.beanFactory == null) {
					throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory");
				}
				// beanName
				String beanName = (String) mapValue;
				//       
				if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) {
					ObjectName objectName = registerLazyInit(beanName, beanKey);
					replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
					return objectName;
				}
				else {
					//   bean  
					Object bean = this.beanFactory.getBean(beanName);
					//   bean  
					ObjectName objectName = registerBeanInstance(bean, beanKey);
					replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
					return objectName;
				}
			}
			else {
				//   Bean,     
				if (this.beanFactory != null) {
					Map<String, ?> beansOfSameType =
							this.beanFactory.getBeansOfType(mapValue.getClass(), false, this.allowEagerInit);
					for (Map.Entry<String, ?> entry : beansOfSameType.entrySet()) {
						if (entry.getValue() == mapValue) {
							String beanName = entry.getKey();
							ObjectName objectName = registerBeanInstance(mapValue, beanKey);
							replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
							return objectName;
						}
					}
				}
				return registerBeanInstance(mapValue, beanKey);
			}
		}
		catch (Exception ex) {
			throw new UnableToRegisterMBeanException(
					"Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
		}
	}
	
	/**
	 * Replaces any bean names used as keys in the <code>NotificationListener</code>
	 * mappings with their corresponding <code>ObjectName</code> values.
	 * @param beanName the name of the bean to be registered
	 * @param objectName the <code>ObjectName</code> under which the bean will be registered
	 * with the <code>MBeanServer</code>
	 */
	private void replaceNotificationListenerBeanNameKeysIfNecessary(String beanName, ObjectName objectName) {
		if (this.notificationListeners != null) {
			for (NotificationListenerBean notificationListener : this.notificationListeners) {
				notificationListener.replaceObjectName(beanName, objectName);
			}
		}
	}

	/**
	 *   MBeanServer         MBean     Bean Mbean   Bean
	 */
	private ObjectName registerBeanInstance(Object bean, String beanKey) throws JMException {
		//   ObjectName
		ObjectName objectName = getObjectName(bean, beanKey);
		Object mbeanToExpose = null;
		//    Mbean,      bean    bean
		if (isMBean(bean.getClass())) {
			mbeanToExpose = bean;
		}
		else {
			//         Mbean
			DynamicMBean adaptedBean = adaptMBeanIfPossible(bean);
			//     Mbean     Bean   Bean
			if (adaptedBean != null) {
				mbeanToExpose = adaptedBean;
			}
		}
		//       mbean    null
		if (mbeanToExpose != null) {
			if (logger.isInfoEnabled()) {
				logger.info("Located MBean '" + beanKey + "': registering with JMX server as MBean [" +
						objectName + "]");
			}
			//   mbean
			doRegister(mbeanToExpose, objectName);
		}
		else {
			if (logger.isInfoEnabled()) {
				logger.info("Located managed bean '" + beanKey + "': registering with JMX server as MBean [" +
						objectName + "]");
			}
			//          ModelMBean
			ModelMBean mbean = createAndConfigureMBean(bean, beanKey);
			//   ModelMBean
			doRegister(mbean, objectName);
			injectNotificationPublisherIfNecessary(bean, mbean, objectName);
		}
		return objectName;
	}

	/**
	 *            bean     MBeanServer  bean
	 */
	private ObjectName registerLazyInit(String beanName, String beanKey) throws JMException {
		
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setProxyTargetClass(true);
		proxyFactory.setFrozen(true);

		if (isMBean(this.beanFactory.getType(beanName))) {
			// A straight MBean... Let's create a simple lazy-init CGLIB proxy for it.
			LazyInitTargetSource targetSource = new LazyInitTargetSource();
			targetSource.setTargetBeanName(beanName);
			targetSource.setBeanFactory(this.beanFactory);
			proxyFactory.setTargetSource(targetSource);

			Object proxy = proxyFactory.getProxy(this.beanClassLoader);
			ObjectName objectName = getObjectName(proxy, beanKey);
			if (logger.isDebugEnabled()) {
				logger.debug("Located MBean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
						objectName + "]");
			}
			doRegister(proxy, objectName);
			return objectName;
		}

		else {
			// A simple bean... Let's create a lazy-init ModelMBean proxy with notification support.
			NotificationPublisherAwareLazyTargetSource targetSource = new NotificationPublisherAwareLazyTargetSource();
			targetSource.setTargetBeanName(beanName);
			targetSource.setBeanFactory(this.beanFactory);
			proxyFactory.setTargetSource(targetSource);

			Object proxy = proxyFactory.getProxy(this.beanClassLoader);
			ObjectName objectName = getObjectName(proxy, beanKey);
			if (logger.isDebugEnabled()) {
				logger.debug("Located simple bean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
						objectName + "]");
			}
			ModelMBean mbean = createAndConfigureMBean(proxy, beanKey);
			targetSource.setModelMBean(mbean);
			targetSource.setObjectName(objectName);
			doRegister(mbean, objectName);
			return objectName;
		}
	}

	/**
	 *     bean ObjectName
	 *   bean   SelfNaming  ,ObjectName   SelfNaming   getObjectName()    
	 *    ,      ObjectNamingStrategy
	 */
	protected ObjectName getObjectName(Object bean, String beanKey) throws MalformedObjectNameException {
		if (bean instanceof SelfNaming) {
			return ((SelfNaming) bean).getObjectName();
		}
		else {
			return this.namingStrategy.getObjectName(bean, beanKey);
		}
	}

	/**
	 *     Bean   MBean
	 */
	protected boolean isMBean(Class beanClass) {
		return JmxUtils.isMBean(beanClass);
	}

	/**
	 *      ,    Bean      MBean
	 */
	@SuppressWarnings("unchecked")
	protected DynamicMBean adaptMBeanIfPossible(Object bean) throws JMException {
	     //    Bean    
		Class targetClass = AopUtils.getTargetClass(bean);
		//     class   bean class
		if (targetClass != bean.getClass()) {
			//   MXBean   
			Class ifc = JmxUtils.getMXBeanInterface(targetClass);
			//       null
			if (ifc != null) {
				if (!(ifc.isInstance(bean))) {
					throw new NotCompliantMBeanException("Managed bean [" + bean +
							"] has a target class with an MXBean interface but does not expose it in the proxy");
				}
				//        Mbean  
				return new StandardMBean(bean, ifc, true);
			}
			else {
				//   MBean  
				ifc = JmxUtils.getMBeanInterface(targetClass);
				if (ifc != null) {
					if (!(ifc.isInstance(bean))) {
						throw new NotCompliantMBeanException("Managed bean [" + bean +
								"] has a target class with an MBean interface but does not expose it in the proxy");
					}
					//        MBean    
					return new StandardMBean(bean, ifc);
				}
			}
		}
		//  Bean    MXBean       MBean  
		return null;
	}

	/**
	 *                         Mbean
	 */
	protected ModelMBean createAndConfigureMBean(Object managedResource, String beanKey)
			throws MBeanExportException {
		try {
			//       ModelMBean
			ModelMBean mbean = createModelMBean();
			//   modelMBeanInfo
			mbean.setModelMBeanInfo(getMBeanInfo(managedResource, beanKey));
			//   ManagedResource
			mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
			return mbean;
		}
		catch (Exception ex) {
			throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
					managedResource + "] with key '" + beanKey + "'", ex);
		}
	}

	/**
	 *       ModelMBean     。         bean          ModelMBean  
	 *        bean        ,            ModelMbean   
	 */
	protected ModelMBean createModelMBean() throws MBeanException {
		return (this.exposeManagedResourceClassLoader ? new SpringModelMBean() : new RequiredModelMBean());
	}

	
	private ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException {
		ModelMBeanInfo info = this.assembler.getMBeanInfo(managedBean, beanKey);
		if (logger.isWarnEnabled() && ObjectUtils.isEmpty(info.getAttributes()) &&
				ObjectUtils.isEmpty(info.getOperations())) {
			logger.warn("Bean with key '" + beanKey +
					"' has been registered as an MBean but has no exposed attributes or operations");
		}
		return info;
	}


	//---------------------------------------------------------------------
	// Autodetection process
	//---------------------------------------------------------------------

	
	private void autodetectBeans(final AutodetectCapableMBeanInfoAssembler assembler) {
		autodetect(new AutodetectCallback() {
			public boolean include(Class beanClass, String beanName) {
				return assembler.includeBean(beanClass, beanName);
			}
		});
	}

	/**
	 *                  MBean,    MBeanServer    
	 */
	private void autodetectMBeans() {
		autodetect(new AutodetectCallback() {
			public boolean include(Class beanClass, String beanName) {
				return isMBean(beanClass);
			}
		});
	}

	/**
	 *           ,   AutodetectCallback         Bean    
	 */
	private void autodetect(AutodetectCallback callback) {
	   //      BeanNames Set
		Set<String> beanNames = new LinkedHashSet<String>(this.beanFactory.getBeanDefinitionCount());
		//        Bean
		beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames()));
	    // 
		if (this.beanFactory instanceof ConfigurableBeanFactory) {
			beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames()));
		}
		//     Bean
		for (String beanName : beanNames) {
			if (!isExcluded(beanName) && !isBeanDefinitionAbstract(this.beanFactory, beanName)) {
				try {
				//   bean Class  
					Class beanClass = this.beanFactory.getType(beanName);
					//   beanClass  null        bean
					if (beanClass != null && callback.include(beanClass, beanName)) {
						//    Bean       
						boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName);
						//              Bean   ,    null
						Object beanInstance = (!lazyInit ? this.beanFactory.getBean(beanName) : null);
							//   beans     bean  bean    null, beans      bean
						if (!this.beans.containsValue(beanName) && (beanInstance == null ||
								!CollectionUtils.containsInstance(this.beans.values(), beanInstance))) {
							//     JMX
							this.beans.put(beanName, (beanInstance != null ? beanInstance : beanName));
							if (logger.isInfoEnabled()) {
								logger.info("Bean with name '" + beanName + "' has been autodetected for JMX exposure");
							}
						}
						else {
							if (logger.isDebugEnabled()) {
								logger.debug("Bean with name '" + beanName + "' is already registered for JMX exposure");
							}
						}
					}
				}
				catch (CannotLoadBeanClassException ex) {
					if (this.allowEagerInit) {
						throw ex;
					}
					// otherwise ignore beans where the class is not resolvable
				}
			}
		}
	}

	/**
	 * Indicates whether or not a particular bean name is present in the excluded beans list.
	 */
	private boolean isExcluded(String beanName) {
		return (this.excludedBeans != null &&
				(this.excludedBeans.contains(beanName) ||
						(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
								this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length())))));
	}

	/**
	 * Return whether the specified bean definition should be considered as abstract.
	 */
	private boolean isBeanDefinitionAbstract(ListableBeanFactory beanFactory, String beanName) {
		return (beanFactory instanceof ConfigurableListableBeanFactory && beanFactory.containsBeanDefinition(beanName) &&
				((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName).isAbstract());
	}


	//---------------------------------------------------------------------
	// Notification and listener management
	//---------------------------------------------------------------------

	/**
	 * If the supplied managed resource implements the {@link NotificationPublisherAware} an instance of
	 * {@link org.springframework.jmx.export.notification.NotificationPublisher} is injected.
	 */
	private void injectNotificationPublisherIfNecessary(
			Object managedResource, ModelMBean modelMBean, ObjectName objectName) {

		if (managedResource instanceof NotificationPublisherAware) {
			((NotificationPublisherAware) managedResource).setNotificationPublisher(
					new ModelMBeanNotificationPublisher(modelMBean, objectName, managedResource));
		}
	}

	/**
	 *         
	 * with the {@link MBeanServer}.
	 */
	private void registerNotificationListeners() throws MBeanExportException {
	      //            
		if (this.notificationListeners != null) {
			//      
			for (NotificationListenerBean bean : this.notificationListeners) {
				try {
					//  ObjectName  
					ObjectName[] mappedObjectNames = bean.getResolvedObjectNames();
					if (mappedObjectNames == null) {
						// Mapped to all MBeans registered by the MBeanExporter.
						mappedObjectNames = getRegisteredObjectNames();
					}
					if (this.registeredNotificationListeners.put(bean, mappedObjectNames) == null) {
						for (ObjectName mappedObjectName : mappedObjectNames) {
						   //  server      
							this.server.addNotificationListener(mappedObjectName, bean.getNotificationListener(),
									bean.getNotificationFilter(), bean.getHandback());
						}
					}
				}
				catch (Exception ex) {
					throw new MBeanExportException("Unable to register NotificationListener", ex);
				}
			}
		}
	}

	/**
	 *      
	 * from the {@link MBeanServer}.
	 */
	private void unregisterNotificationListeners() {
		for (Map.Entry<NotificationListenerBean, ObjectName[]> entry : this.registeredNotificationListeners.entrySet()) {
			NotificationListenerBean bean = entry.getKey();
			ObjectName[] mappedObjectNames = entry.getValue();
			for (ObjectName mappedObjectName : mappedObjectNames) {
				try {
					this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(),
							bean.getNotificationFilter(), bean.getHandback());
				}
				catch (Exception ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Unable to unregister NotificationListener", ex);
					}
				}
			}
		}
		this.registeredNotificationListeners.clear();
	}

	/**
	 * Called when an MBean is registered. Notifies all registered
	 * {@link MBeanExporterListener MBeanExporterListeners} of the registration event.
	 * <p>Please note that if an {@link MBeanExporterListener} throws a (runtime)
	 * exception when notified, this will essentially interrupt the notification process
	 * and any remaining listeners that have yet to be notified will not (obviously)
	 * receive the {@link MBeanExporterListener#mbeanRegistered(javax.management.ObjectName)}
	 * callback.
	 * @param objectName the <code>ObjectName</code> of the registered MBean
	 */
	@Override
	protected void onRegister(ObjectName objectName) {
		notifyListenersOfRegistration(objectName);
	}

	/**
	 * Called when an MBean is unregistered. Notifies all registered
	 * {@link MBeanExporterListener MBeanExporterListeners} of the unregistration event.
	 * <p>Please note that if an {@link MBeanExporterListener} throws a (runtime)
	 * exception when notified, this will essentially interrupt the notification process
	 * and any remaining listeners that have yet to be notified will not (obviously)
	 * receive the {@link MBeanExporterListener#mbeanUnregistered(javax.management.ObjectName)}
	 * callback.
	 * @param objectName the <code>ObjectName</code> of the unregistered MBean
	 */
	@Override
	protected void onUnregister(ObjectName objectName) {
		notifyListenersOfUnregistration(objectName);
	}


    /**
	 * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
	 * registration of the MBean identified by the supplied {@link ObjectName}.
	 */
	private void notifyListenersOfRegistration(ObjectName objectName) {
		if (this.listeners != null) {
			for (MBeanExporterListener listener : this.listeners) {
				listener.mbeanRegistered(objectName);
			}
		}
	}

	/**
	 * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
	 * unregistration of the MBean identified by the supplied {@link ObjectName}.
	 */
	private void notifyListenersOfUnregistration(ObjectName objectName) {
		if (this.listeners != null) {
			for (MBeanExporterListener listener : this.listeners) {
				listener.mbeanUnregistered(objectName);
			}
		}
	}


	//---------------------------------------------------------------------
	// Inner classes for internal use
	//---------------------------------------------------------------------

	/**
	 *       ,
	 */
	private static interface AutodetectCallback {

		/**
		 * Called during the autodetection process to decide whether
		 * or not a bean should be included.
		 * @param beanClass the class of the bean
		 * @param beanName the name of the bean
		 */
		boolean include(Class beanClass, String beanName);
	}


	/**
	 * Extension of {@link LazyInitTargetSource} that will inject a
	 * {@link org.springframework.jmx.export.notification.NotificationPublisher}
	 * into the lazy resource as it is created if required.
	 */
	private class NotificationPublisherAwareLazyTargetSource extends LazyInitTargetSource {

		private ModelMBean modelMBean;
		
		private ObjectName objectName;

		public void setModelMBean(ModelMBean modelMBean) {
			this.modelMBean = modelMBean;
		}

		public void setObjectName(ObjectName objectName) {
			this.objectName = objectName;
		}

		@Override
		protected void postProcessTargetObject(Object targetObject) {
			injectNotificationPublisherIfNecessary(targetObject, this.modelMBean, this.objectName);
		}
	}

}