Java tutorial
/* * Copyright 2002-2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.jmx.export; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.modelmbean.InvalidTargetObjectTypeException; import javax.management.modelmbean.ModelMBean; import javax.management.modelmbean.ModelMBeanInfo; import javax.management.modelmbean.RequiredModelMBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.target.LazyInitTargetSource; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.Constants; import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler; import org.springframework.jmx.export.assembler.MBeanInfoAssembler; import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler; import org.springframework.jmx.export.naming.KeyNamingStrategy; import org.springframework.jmx.export.naming.ObjectNamingStrategy; import org.springframework.jmx.export.naming.SelfNaming; import org.springframework.jmx.support.JmxUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** * A bean that allows for any Spring-managed bean to be exposed to a JMX * <code>MBeanServer</code>, without the need to define any JMX-specific * information in the bean classes. * * <p>If the bean implements one of the JMX management interfaces then * <code>MBeanExporter</code> can simply register the MBean with the server * automatically, through its autodetection process. * * <p>If the bean does not implement one of the JMX management interfaces then * <code>MBeanExporter</code> will create the management information using the * supplied <code>MBeanInfoAssembler</code> implementation. * * <p>A list of <code>MBeanExporterListener</code>s can be registered via the * <code>listeners</code> property, allowing application code to be notified * of MBean registration and unregistration events. * * @author Rob Harrop * @author Juergen Hoeller * @since 1.2 * @see #setBeans * @see #setAutodetect * @see #setAssembler * @see #setListeners * @see org.springframework.jmx.export.assembler.MBeanInfoAssembler * @see MBeanExporterListener */ public class MBeanExporter implements BeanFactoryAware, InitializingBean, DisposableBean { /** * Constant indicating that registration should fail when * attempting to register an MBean under a name that already exists. * <p>This is the default registration behavior. */ public static final int REGISTRATION_FAIL_ON_EXISTING = 0; /** * Constant indicating that registration should ignore the affected MBean * when attempting to register an MBean under a name that already exists. */ public static final int REGISTRATION_IGNORE_EXISTING = 1; /** * Constant indicating that registration should replace the affected MBean * when attempting to register an MBean under a name that already exists. */ public static final int REGISTRATION_REPLACE_EXISTING = 2; /** * Constant for the JMX <code>mr_type</code> "ObjectReference". */ private static final String MR_TYPE_OBJECT_REFERENCE = "ObjectReference"; /** * Constants for this class. */ private static final Constants constants = new Constants(MBeanExporter.class); /** * <code>Log</code> instance for this class. */ protected final Log logger = LogFactory.getLog(getClass()); /** * The <code>MBeanServer</code> instance being used to register beans. */ private MBeanServer server; /** * The beans to be exposed as JMX managed resources. */ private Map beans; /** * Whether to autodetect MBeans in the bean factory. */ private boolean autodetect = false; /** * A list of bean names that should be excluded from autodetection. */ private Set excludedBeans; /** * Stores the <code>MBeanInfoAssembler</code> to use for this exporter. */ private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler(); /** * The strategy to use for creating <code>ObjectName</code>s for an object. */ private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy(); /** * Stores the <code>BeanFactory</code> for use in autodetection process. */ private ListableBeanFactory beanFactory; /** * The beans that have been registered by this exporter. */ private Set registeredBeans; /** * The <code>MBeanExporterListeners</code> registered with this exporter. */ private MBeanExporterListener[] listeners; /** * The action take when registering an MBean and finding that it already exists. * By default an exception is raised. */ private int registrationBehavior = REGISTRATION_FAIL_ON_EXISTING; /** * Specify the instance <code>MBeanServer</code> with which all beans should * be registered. The <code>MBeanExporter</code> will attempt to locate an * existing <code>MBeanServer</code> if none is supplied. */ public void setServer(MBeanServer server) { this.server = server; } /** * Supply a <code>Map</code> of beans to be registered with the JMX * <code>MBeanServer</code>. * <p>The String keys are the basis for the creation of JMX object names. * By default, a JMX <code>ObjectName</code> will be created straight * from the given key. This can be customized through specifying a * custom <code>NamingStrategy</code>. * <p>Both bean instances and bean names are allowed as values. * Bean instances are typically linked in through bean references. * Bean names will be resolved as beans in the current factory, respecting * lazy-init markers (that is, not triggering initialization of such beans). * @param beans Map with bean instances or bean names as values * @see #setNamingStrategy * @see org.springframework.jmx.export.naming.KeyNamingStrategy * @see javax.management.ObjectName#ObjectName(String) */ public void setBeans(Map beans) { this.beans = beans; } /** * Set whether to autodetect MBeans in the bean factory that this exporter * runs in. Will also ask an <code>AutodetectCapableMBeanInfoAssembler</code> * if available. * <p>This feature is turned off by default. Explicitly specify "true" here * to enable autodetection. * @see #setAssembler * @see AutodetectCapableMBeanInfoAssembler * @see org.springframework.jmx.support.JmxUtils#isMBean */ public void setAutodetect(boolean autodetect) { this.autodetect = autodetect; } /** * Set the list of names for beans that should be excluded from autodetection. */ public void setExcludedBeans(String[] excludedBeans) { this.excludedBeans = (excludedBeans != null ? new HashSet(Arrays.asList(excludedBeans)) : null); } /** * Set the implementation of the <code>MBeanInfoAssembler</code> interface to use * for this exporter. Default is a <code>SimpleReflectiveMBeanInfoAssembler</code>. * <p>The passed-in assembler can optionally implement the * <code>AutodetectCapableMBeanInfoAssembler</code> interface, which enables it * to particiapte in the exporter's MBean autodetection process. * @see org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler * @see org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler * @see #setAutodetect */ public void setAssembler(MBeanInfoAssembler assembler) { this.assembler = assembler; } /** * Set the implementation of the <code>ObjectNamingStrategy</code> interface * to use for this exporter. Default is a <code>KeyNamingStrategy</code>. * @see org.springframework.jmx.export.naming.KeyNamingStrategy * @see org.springframework.jmx.export.naming.MetadataNamingStrategy */ public void setNamingStrategy(ObjectNamingStrategy namingStrategy) { this.namingStrategy = namingStrategy; } /** * Set the <code>MBeanExporterListener</code>s that should be notified * of MBean registration and unregistration events. * @see MBeanExporterListener */ public void setListeners(MBeanExporterListener[] listeners) { this.listeners = listeners; } /** * Set the registration behavior by the name of the corresponding constant, * e.g. "REGISTRATION_IGNORE_EXISTING". * @see #setRegistrationBehavior * @see #REGISTRATION_FAIL_ON_EXISTING * @see #REGISTRATION_IGNORE_EXISTING * @see #REGISTRATION_REPLACE_EXISTING */ public void setRegistrationBehaviorName(String registrationBehavior) { setRegistrationBehavior(constants.asNumber(registrationBehavior).intValue()); } /** * Specify what action should be taken when attempting to register an MBean * under an {@link javax.management.ObjectName} that already exists. * <p>Default is REGISTRATION_FAIL_ON_EXISTING. * @see #setRegistrationBehaviorName(String) * @see #REGISTRATION_FAIL_ON_EXISTING * @see #REGISTRATION_IGNORE_EXISTING * @see #REGISTRATION_REPLACE_EXISTING */ public void setRegistrationBehavior(int registrationBehavior) { this.registrationBehavior = registrationBehavior; } /** * This callback is only required for resolution of bean names in the "beans" * <code>Map</code> and for autodetection of MBeans (in the latter case, * a <code>ListableBeanFactory</code> is required). * @see #setBeans * @see #setAutodetect * @see org.springframework.beans.factory.ListableBeanFactory */ public void setBeanFactory(BeanFactory beanFactory) { if (beanFactory instanceof ListableBeanFactory) { this.beanFactory = (ListableBeanFactory) beanFactory; } else { logger.info("Not running in a ListableBeanFactory: autodetection of MBeans not available"); } } /** * Start bean registration automatically when deployed in an * <code>ApplicationContext</code>. * @see #registerBeans() */ public void afterPropertiesSet() throws JMException { // register the beans now registerBeans(); } /** * Registers the defined beans with the <code>MBeanServer</code>. Each bean is exposed * to the <code>MBeanServer</code> via a <code>ModelMBean</code>. The actual implemetation * of the <code>ModelMBean</code> interface used depends on the implementation of the * <code>ModelMBeanProvider</code> interface that is configured. By default the * <code>RequiredModelMBean</code> class that is supplied with all JMX implementations * is used. * <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() throws JMException { // 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. if (this.server == null) { this.server = JmxUtils.locateMBeanServer(); } // The beans property may be <code>null</code>, for example // if we are relying solely on autodetection. if (this.beans == null) { this.beans = new HashMap(); } // Perform autodetection, if desired. if (this.autodetect) { if (this.beanFactory == null) { throw new JMException("Cannot autodetect MBeans if not running in a BeanFactory"); } // Autodetect any beans that are already MBeans. logger.info("Autodetecting user-defined JMX MBeans"); autodetectMBeans(); // Allow the metadata assembler a chance to vote for bean inclusion. if (this.assembler instanceof AutodetectCapableMBeanInfoAssembler) { autodetectBeans((AutodetectCapableMBeanInfoAssembler) this.assembler); } } // Check we now have at least one bean. if (this.beans.isEmpty()) { throw new IllegalArgumentException("Must specify at least one bean for registration"); } this.registeredBeans = new HashSet(this.beans.size()); try { for (Iterator it = this.beans.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String beanKey = (String) entry.getKey(); Object value = entry.getValue(); ObjectName objectName = registerBeanNameOrInstance(value, beanKey); if (objectName != null) { this.registeredBeans.add(objectName); notifyListenersOfRegistration(objectName); } } } catch (InvalidTargetObjectTypeException ex) { // Unregister beans already registered by this exporter. unregisterBeans(); // We should never get this! throw new JMException("An invalid object type was used when specifying a managed resource. " + "This is a serious error and points to an error in the Spring JMX code. Root cause: " + ex.getMessage()); } catch (JMException ex) { // Unregister beans already registered by this exporter. unregisterBeans(); throw ex; } } /** * Registers an individual bean with the <code>MBeanServer</code>. This method * is responsible for deciding <strong>how</strong> a bean should be exposed * to the <code>MBeanServer</code>. Specifically, if the <code>mapValue</code> * is the name of a bean that is configured for lazy initialization, then * a proxy to the resource is registered with the <code>MBeanServer</code> * so that the the lazy load behavior is honored. If the bean is already an * MBean then it will be registered directly with the <code>MBeanServer</code> * without any intervention. For all other beans or bean names, the resource * itself is registered with the <code>MBeanServer</code> directly. * @param beanKey the key associated with this bean in the beans map * @param mapValue the value configured for this bean in the beans map. * May be either the <code>String</code> name of a bean, or the bean itself. * @return the <code>ObjectName</code> under which the resource was registered * @throws JMException in case of an error in the underlying JMX infrastructure * @throws InvalidTargetObjectTypeException an error in the definition of the MBean resource * @see #setBeans * @see #registerLazyInit * @see #registerMBean * @see #registerSimpleBean */ private ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws JMException, InvalidTargetObjectTypeException { if (mapValue instanceof String) { // Bean name pointing to a potentially lazy-init bean in the factory. if (this.beanFactory == null) { throw new JMException("Cannot resolve bean names if not running in a BeanFactory"); } String beanName = (String) mapValue; if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) { if (logger.isDebugEnabled()) { logger.debug("Found bean name for lazy init bean with key [" + beanKey + "]. Registering bean with lazy init support."); } return registerLazyInit(beanName, beanKey); } else { if (logger.isDebugEnabled()) { logger.debug("String value under key [" + beanKey + "] points to a bean that was not " + "registered for lazy initialization. Registering bean normally with JMX server."); } Object bean = this.beanFactory.getBean(beanName); return registerBeanInstance(bean, beanKey); } } else { // Plain bean instance -> register it directly. return registerBeanInstance(mapValue, beanKey); } } /** * Registers an existing MBean or an MBean adapter for a plain bean * with the <code>MBeanServer</code>. * @param beanInstance the bean to register, either an MBean or a plain bean * @param beanKey the key associated with this bean in the beans map * @return the <code>ObjectName</code> under which the bean was registered * with the <code>MBeanServer</code> * @throws JMException an error in the underlying JMX infrastructure */ private ObjectName registerBeanInstance(Object beanInstance, String beanKey) throws JMException, InvalidTargetObjectTypeException { if (JmxUtils.isMBean(beanInstance.getClass())) { if (logger.isDebugEnabled()) { logger.debug("Located MBean under key [" + beanKey + "]: registering with JMX server"); } return registerMBean(beanInstance, beanKey); } else { if (logger.isDebugEnabled()) { logger.debug("Located bean under key [" + beanKey + "] registering with JMX server."); } return registerSimpleBean(beanInstance, beanKey); } } /** * Registers an existing MBean with the <code>MBeanServer</code>. * @param mbean the bean instance to register * @param beanKey the key associated with this bean in the beans map * @return the <code>ObjectName</code> under which the bean was registered * with the <code>MBeanServer</code> * @throws JMException an error in the underlying JMX infrastructure */ private ObjectName registerMBean(Object mbean, String beanKey) throws JMException { try { ObjectName objectName = getObjectName(mbean, beanKey); if (logger.isDebugEnabled()) { logger.debug("Registering MBean [" + objectName + "]"); } return doRegister(mbean, objectName); } catch (MalformedObjectNameException ex) { if (logger.isDebugEnabled()) { logger.debug("Unable to register MBean [" + mbean + "] with key [" + beanKey + "]"); } return null; } } /** * Registers a plain bean as MBean with the <code>MBeanServer</code>. * The management interface for the bean is created by the configured * <code>MBeanInfoAssembler</code>. * @param bean the bean instance to register * @param beanKey the key associated with this bean in the beans map * @return the <code>ObjectName</code> under which the bean was registered * with the <code>MBeanServer</code> * @throws JMException in case of an error in the underlying JMX infrastructure * @throws InvalidTargetObjectTypeException an error in the definition of the MBean resource */ private ObjectName registerSimpleBean(Object bean, String beanKey) throws JMException, InvalidTargetObjectTypeException { ObjectName objectName = getObjectName(bean, beanKey); if (logger.isDebugEnabled()) { logger.debug("Registering and assembling MBean [" + objectName + "]"); } ModelMBean mbean = createModelMBean(); mbean.setModelMBeanInfo(getMBeanInfo(bean, beanKey)); mbean.setManagedResource(bean, MR_TYPE_OBJECT_REFERENCE); return doRegister(mbean, objectName); } /** * Registers beans that are configured for lazy initialization with the * <code>MBeanServer<code> indirectly through a proxy. * @param beanName the name of the bean in the <code>BeanFactory</code> * @param beanKey the key associated with this bean in the beans map * @return the <code>ObjectName</code> under which the bean was registered * with the <code>MBeanServer</code> * @throws JMException an error in the underlying JMX infrastructure * @throws InvalidTargetObjectTypeException an error in the definition of the MBean resource */ private ObjectName registerLazyInit(String beanName, String beanKey) throws JMException, InvalidTargetObjectTypeException { LazyInitTargetSource targetSource = new LazyInitTargetSource(); targetSource.setTargetBeanName(beanName); targetSource.setBeanFactory(this.beanFactory); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTargetSource(targetSource); proxyFactory.setProxyTargetClass(true); proxyFactory.setFrozen(true); Object proxy = proxyFactory.getProxy(); ObjectName objectName = getObjectName(proxy, beanKey); if (logger.isDebugEnabled()) { logger.debug("Registering lazy-init MBean [" + objectName + "]"); } ModelMBean mbean = createModelMBean(); mbean.setModelMBeanInfo(getMBeanInfo(proxy, beanKey)); mbean.setManagedResource(proxy, MR_TYPE_OBJECT_REFERENCE); return doRegister(mbean, objectName); } /** * Actually registers the MBean with the server. The behavior when encountering * an existing MBean can be configured using the {@link #setRegistrationBehavior(int)} * and {@link #setRegistrationBehaviorName(String)} methods. */ private ObjectName doRegister(Object mbean, ObjectName objectName) throws JMException { ObjectInstance registeredBean = null; try { registeredBean = this.server.registerMBean(mbean, objectName); } catch (InstanceAlreadyExistsException ex) { if (this.registrationBehavior == REGISTRATION_IGNORE_EXISTING) { if (logger.isDebugEnabled()) { logger.debug("Ignoring existing MBean at [" + objectName + "]"); } } else if (this.registrationBehavior == REGISTRATION_REPLACE_EXISTING) { try { if (logger.isDebugEnabled()) { logger.debug("Replacing existing MBean at [" + objectName + "]"); } this.server.unregisterMBean(objectName); registeredBean = this.server.registerMBean(mbean, objectName); } catch (InstanceNotFoundException ex2) { throw new IllegalStateException( "Unable to replace existing MBean at [" + objectName + "]: " + ex.getMessage()); } } else { throw ex; } } // Track registration and notify listeners. ObjectName actualObjectName = (registeredBean != null ? registeredBean.getObjectName() : null); if (actualObjectName == null) { actualObjectName = objectName; } return actualObjectName; } /** * Retrieve the <code>ObjectName</code> for a bean. * <p>If the bean implements the <code>SelfNaming</code> interface, then the * <code>ObjectName</code> will be retrieved using <code>SelfNaming.getObjectName()</code>. * Otherwise, the configured <code>ObjectNamingStrategy</code> is used. * @param bean the name of the bean in the <code>BeanFactory</code> * @param beanKey the key associated with the bean in the beans map * @return the <code>ObjectName</code> for the supplied bean * @throws MalformedObjectNameException if the retrieved <code>ObjectName</code> is malformed. */ private ObjectName getObjectName(Object bean, String beanKey) throws MalformedObjectNameException { if (bean instanceof SelfNaming) { return ((SelfNaming) bean).getObjectName(); } else { return this.namingStrategy.getObjectName(bean, beanKey); } } /** * Gets the <code>ModelMBeanInfo</code> for the bean with the supplied key * and of the supplied type. */ 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 registed as an MBean but has no exposed attributes or operations"); } return info; } /** * Attempts to detect any beans defined in the <code>ApplicationContext</code> that are * valid MBeans and registers them automatically with the <code>MBeanServer</code>. */ private void autodetectMBeans() { autodetect(new AutodetectCallback() { public boolean include(Class beanClass, String beanName) { return JmxUtils.isMBean(beanClass); } }); } /** * Invoked when using an <code>AutodetectCapableMBeanInfoAssembler</code>. * Gives the assembler the opportunity to add additional beans from the * <code>BeanFactory</code> to the list of beans to be exposed via JMX. * <p>This implementation prevents a bean from being added to the list * automatically if it has already been added manually, and it prevents * certain internal classes from being registered automatically. */ private void autodetectBeans(final AutodetectCapableMBeanInfoAssembler assembler) { autodetect(new AutodetectCallback() { public boolean include(Class beanClass, String beanName) { return assembler.includeBean(beanClass, beanName); } }); } /** * Performs the actual autodetection process, delegating to an instance * <code>AutodetectCallback</code> to vote on the inclusion of a given bean. * @param callback the <code>AutodetectCallback</code> to use when deciding * whether to include a bean or not */ private void autodetect(AutodetectCallback callback) { String[] beanNames = this.beanFactory.getBeanNamesForType(null); for (int i = 0; i < beanNames.length; i++) { String beanName = beanNames[i]; if (!isExcluded(beanName)) { Class beanClass = this.beanFactory.getType(beanName); if (beanClass != null && callback.include(beanClass, beanName)) { boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName); Object beanInstance = (!lazyInit ? this.beanFactory.getBean(beanName) : null); if (!this.beans.containsValue(beanName) && (beanInstance == null || !CollectionUtils.containsInstance(this.beans.values(), beanInstance))) { // Not already registered for JMX exposure. 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"); } } } } } } /** * Return whether the specified bean definition should be considered as lazy-init. * @param beanFactory the bean factory that is supposed to contain the bean definition * @param beanName the name of the bean to check * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition * @see org.springframework.beans.factory.config.BeanDefinition#isLazyInit */ protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, String beanName) { if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { return false; } try { BeanDefinition bd = ((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName); return bd.isLazyInit(); } catch (NoSuchBeanDefinitionException ex) { // Probably a directly registered singleton. return false; } } /** * Create an instance of a class that implements <code>ModelMBean</code>. * <p>This method is called to obtain a <code>ModelMBean</code> instance to * use when registering a bean. This method is called once per bean during the * registration phase and must return a new instance of <code>ModelMBean</code> * @return a new instance of a class that implements <code>ModelMBean</code> * @throws MBeanException if creation of the ModelMBean failed */ protected ModelMBean createModelMBean() throws MBeanException { return new RequiredModelMBean(); } /** * 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)); } /** * Notifies all registered <code>MBeanExporterListener</code> that an MBean * with the supplied <code>ObjectName</code> has been registered. * @param objectName the <code>ObjectName</code> of the registered MBean * @see MBeanExporterListener */ private void notifyListenersOfRegistration(ObjectName objectName) { if (this.listeners != null) { for (int i = 0; i < this.listeners.length; i++) { MBeanExporterListener listener = this.listeners[i]; listener.mbeanRegistered(objectName); } } } /** * Notifies all registered <code>MBeanExporterListener</code> that an MBean * with the supplied <code>ObjectName</code> has been unregistered. * @param objectName the <code>ObjectName</code> of the registered MBean * @see MBeanExporterListener */ private void notifyListenersOfUnregistration(ObjectName objectName) { if (this.listeners != null) { for (int i = 0; i < this.listeners.length; i++) { MBeanExporterListener listener = this.listeners[i]; listener.mbeanUnregistered(objectName); } } } /** * Unregisters all beans that this exported has exposed via JMX * when the enclosing <code>ApplicationContext</code> is destroyed. */ public void destroy() { unregisterBeans(); } /** * Unregisters all beans that this exported has exposed via JMX. */ private void unregisterBeans() { logger.info("Unregistering JMX-exposed beans on shutdown"); for (Iterator it = this.registeredBeans.iterator(); it.hasNext();) { ObjectName objectName = (ObjectName) it.next(); try { // MBean might already have been unregistered by an external process. if (this.server.isRegistered(objectName)) { this.server.unregisterMBean(objectName); notifyListenersOfUnregistration(objectName); } else { if (logger.isWarnEnabled()) { logger.warn("Could not unregister MBean [" + objectName + "] as said MBean " + "is not registered (perhaps already unregistered by an external process)"); } } } catch (JMException ex) { if (logger.isErrorEnabled()) { logger.error("Could not unregister MBean [" + objectName + "]", ex); } } } this.registeredBeans.clear(); } /** * Internal callback interface for the autodetection process. */ private static interface AutodetectCallback { /** * Called during the autodetection process to decide whether * or not a bean should be include. * @param beanClass the class of the bean * @param beanName the name of the bean */ boolean include(Class beanClass, String beanName); } }