打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Tomcat7中的JMX使用(二)Dynamic MBean

 

接触过动态MBean的朋友一定知道,它的实例肯定要实现一个接口,即javax.management.DynamicMBean。实现这个接口就意味着同时要实现它下面的6个方法:

Java代码  
  1. public Object getAttribute(String attribute) throws AttributeNotFoundException,MBeanException, ReflectionException;   
  2.   
  3. public void setAttribute(Attribute attribute) throws AttributeNotFoundException,InvalidAttributeValueException, MBeanException, ReflectionException ;   
  4.   
  5. public AttributeList getAttributes(String[] attributes);  
  6.   
  7. public AttributeList setAttributes(AttributeList attributes);  
  8.   
  9. public Object invoke(String actionName, Object params[], String signature[]) throws MBeanException, ReflectionException ;      
  10.   
  11. public MBeanInfo getMBeanInfo();  
public Object getAttribute(String attribute) throws AttributeNotFoundException,MBeanException, ReflectionException; public void setAttribute(Attribute attribute) throws AttributeNotFoundException,InvalidAttributeValueException, MBeanException, ReflectionException ; public AttributeList getAttributes(String[] attributes); public AttributeList setAttributes(AttributeList attributes); public Object invoke(String actionName, Object params[], String signature[]) throws MBeanException, ReflectionException ; public MBeanInfo getMBeanInfo();

通过实现这个通用接口,jvm允许程序在运行时获取和设置MBean公开的属性和调用MBean上公开的方法。

 

上面简要介绍了动态MBean的实现方式,Tomcat中的实际情况比这个要复杂。因为要生成很多种MBean,如果每种类型都用代码写一个MBean就失去了动态MBean的威力,Tomcat7中实际是通过配置文件(即每个组件所在的包下面的mbeans-descriptors.xml)结合通用的动态MBean(org.apache.tomcat.util.modeler.BaseModelMBean)、描述MBean配置信息的org.apache.tomcat.util.modeler.ManagedBean来简化MBean的构造。(笔者注:实际就是用动态MBean实现了模型MBean的功能)

 

一般情况下动态MBean的产生分为两个阶段:一、加载org.apache.tomcat.util.modeler.ManagedBean对象,二、注册MBean实例。

 

1.加载org.apache.tomcat.util.modeler.ManagedBean对象

在Tomcat启动时加载的配置文件server.xml中有这么一行配置:

Xml代码  
  1. <Listener className='org.apache.catalina.mbeans.GlobalResourcesLifecycleListener' />  
<Listener className='org.apache.catalina.mbeans.GlobalResourcesLifecycleListener' />
因此在Tomcat启动时将加载这个类,在这个类中有一个静态成员变量registry:
Java代码  
  1. /** 
  2.  * The configuration information registry for our managed beans. 
  3.  */  
  4. protected static Registry registry = MBeanUtils.createRegistry();  
/** * The configuration information registry for our managed beans. */ protected static Registry registry = MBeanUtils.createRegistry();
也就是说类加载时registry就会获得Registry类的实例,这个Registry类很重要,在MBean的构造过程中将会多次涉及这个类里的方法。先看看MBeanUtils.createRegistry()方法:
Java代码  
  1. /** 
  2.  * Create and configure (if necessary) and return the registry of 
  3.  * managed object descriptions. 
  4.  */  
  5. public static synchronized Registry createRegistry() {  
  6.   
  7.     if (registry == null) {  
  8.         registry = Registry.getRegistry(nullnull);  
  9.         ClassLoader cl = MBeanUtils.class.getClassLoader();  
  10.   
  11.         registry.loadDescriptors('org.apache.catalina.mbeans',  cl);  
  12.         registry.loadDescriptors('org.apache.catalina.authenticator', cl);  
  13.         registry.loadDescriptors('org.apache.catalina.core', cl);  
  14.         registry.loadDescriptors('org.apache.catalina', cl);  
  15.         registry.loadDescriptors('org.apache.catalina.deploy', cl);  
  16.         registry.loadDescriptors('org.apache.catalina.loader', cl);  
  17.         registry.loadDescriptors('org.apache.catalina.realm', cl);  
  18.         registry.loadDescriptors('org.apache.catalina.session', cl);  
  19.         registry.loadDescriptors('org.apache.catalina.startup', cl);  
  20.         registry.loadDescriptors('org.apache.catalina.users', cl);  
  21.         registry.loadDescriptors('org.apache.catalina.ha', cl);  
  22.         registry.loadDescriptors('org.apache.catalina.connector', cl);  
  23.         registry.loadDescriptors('org.apache.catalina.valves',  cl);  
  24.     }  
  25.     return (registry);  
  26.   
  27. }  
/** * Create and configure (if necessary) and return the registry of * managed object descriptions. */ public static synchronized Registry createRegistry() { if (registry == null) { registry = Registry.getRegistry(null, null); ClassLoader cl = MBeanUtils.class.getClassLoader(); registry.loadDescriptors('org.apache.catalina.mbeans', cl); registry.loadDescriptors('org.apache.catalina.authenticator', cl); registry.loadDescriptors('org.apache.catalina.core', cl); registry.loadDescriptors('org.apache.catalina', cl); registry.loadDescriptors('org.apache.catalina.deploy', cl); registry.loadDescriptors('org.apache.catalina.loader', cl); registry.loadDescriptors('org.apache.catalina.realm', cl); registry.loadDescriptors('org.apache.catalina.session', cl); registry.loadDescriptors('org.apache.catalina.startup', cl); registry.loadDescriptors('org.apache.catalina.users', cl); registry.loadDescriptors('org.apache.catalina.ha', cl); registry.loadDescriptors('org.apache.catalina.connector', cl); registry.loadDescriptors('org.apache.catalina.valves', cl); } return (registry); }
注意第8行Registry.getRegistry(null, null)方法的调用,看下它的实现就会发现返回的实际是Registry类的静态变量,这种调用后面会多次看到。接着还需要看一下MBeanUtils类的registry的定义:
Java代码  
  1. /** 
  2.  * The configuration information registry for our managed beans. 
  3.  */  
  4. private static Registry registry = createRegistry();  
/** * The configuration information registry for our managed beans. */ private static Registry registry = createRegistry();
因为此时MBeanUtils类还没在JVM里面加载过,它的成员变量registry为null,所以会调用Registry.getRegistry(null, null)方法构造对象,接下来会多次调用loadDescriptors方法,以下面这一句代码为例:
Java代码  
  1. registry.loadDescriptors('org.apache.catalina.connector', cl);  
registry.loadDescriptors('org.apache.catalina.connector', cl);
这里org.apache.catalina.connector实际上是一个package的路径全名,看下loadDescriptors方法:
Java代码  
  1. /** Lookup the component descriptor in the package and 
  2.  * in the parent packages. 
  3.  * 
  4.  * @param packageName 
  5.  */  
  6. public void loadDescriptors( String packageName, ClassLoader classLoader  ) {  
  7.     String res=packageName.replace( '.''/');  
  8.   
  9.     if( log.isTraceEnabled() ) {  
  10.         log.trace('Finding descriptor '   res );  
  11.     }  
  12.   
  13.     if( searchedPaths.get( packageName ) != null ) {  
  14.         return;  
  15.     }  
  16.     String descriptors=res   '/mbeans-descriptors.ser';  
  17.   
  18.     URL dURL=classLoader.getResource( descriptors );  
  19.   
  20.     if( dURL == null ) {  
  21.         descriptors=res   '/mbeans-descriptors.xml';  
  22.         dURL=classLoader.getResource( descriptors );  
  23.     }  
  24.     if( dURL == null ) {  
  25.         return;  
  26.     }  
  27.   
  28.     log.debug( 'Found '   dURL);  
  29.     searchedPaths.put( packageName,  dURL );  
  30.     try {  
  31.         if( descriptors.endsWith('.xml' ))  
  32.             loadDescriptors('MbeansDescriptorsDigesterSource', dURL, null);  
  33.         else  
  34.             loadDescriptors('MbeansDescriptorsSerSource', dURL, null);  
  35.         return;  
  36.     } catch(Exception ex ) {  
  37.         log.error('Error loading '   dURL);  
  38.     }  
  39.   
  40.     return;  
  41. }  
/** Lookup the component descriptor in the package and * in the parent packages. * * @param packageName */ public void loadDescriptors( String packageName, ClassLoader classLoader ) { String res=packageName.replace( '.', '/'); if( log.isTraceEnabled() ) { log.trace('Finding descriptor ' res ); } if( searchedPaths.get( packageName ) != null ) { return; } String descriptors=res '/mbeans-descriptors.ser'; URL dURL=classLoader.getResource( descriptors ); if( dURL == null ) { descriptors=res '/mbeans-descriptors.xml'; dURL=classLoader.getResource( descriptors ); } if( dURL == null ) { return; } log.debug( 'Found ' dURL); searchedPaths.put( packageName, dURL ); try { if( descriptors.endsWith('.xml' )) loadDescriptors('MbeansDescriptorsDigesterSource', dURL, null); else loadDescriptors('MbeansDescriptorsSerSource', dURL, null); return; } catch(Exception ex ) { log.error('Error loading ' dURL); } return; }
第13到15行是先在Registry类的缓存searchedPaths中查找是否已经加载了该package所对应的配置文件,如果没有在第16到18行会在该包路径下面查找是否有mbeans-descriptors.ser文件,没有则在第20到23行查找同路径下的mbeans-descriptors.xml文件。找到之后在第29行放入缓存searchedPaths。我们既然以org.apache.catalina.connector为例,则找到的是该路径下的mbeans-descriptors.xml。所以会接着执行第32行loadDescriptors('MbeansDescriptorsDigesterSource', dURL, null):
Java代码  
  1. private void loadDescriptors(String sourceType, Object source,  
  2.         String param) throws Exception {  
  3.     load(sourceType, source, param);  
  4. }  
private void loadDescriptors(String sourceType, Object source, String param) throws Exception { load(sourceType, source, param); }
这段代码会执行load方法:
Java代码  
  1. public List<ObjectName> load( String sourceType, Object source,  
  2.         String param) throws Exception {  
  3.     if( log.isTraceEnabled()) {  
  4.         log.trace('load '   source );  
  5.     }  
  6.     String location=null;  
  7.     String type=null;  
  8.     Object inputsource=null;  
  9.   
  10.     if( source instanceof URL ) {  
  11.         URL url=(URL)source;  
  12.         location=url.toString();  
  13.         type=param;  
  14.         inputsource=url.openStream();  
  15.         if( sourceType == null ) {  
  16.             sourceType = sourceTypeFromExt(location);  
  17.         }  
  18.     } else if( source instanceof File ) {  
  19.         location=((File)source).getAbsolutePath();  
  20.         inputsource=new FileInputStream((File)source);              
  21.         type=param;  
  22.         if( sourceType == null ) {  
  23.             sourceType = sourceTypeFromExt(location);  
  24.         }  
  25.     } else if( source instanceof InputStream ) {  
  26.         type=param;  
  27.         inputsource=source;  
  28.     } else if( source instanceof Class<?> ) {  
  29.         location=((Class<?>)source).getName();  
  30.         type=param;  
  31.         inputsource=source;  
  32.         if( sourceType== null ) {  
  33.             sourceType='MbeansDescriptorsIntrospectionSource';  
  34.         }  
  35.     }  
  36.       
  37.     if( sourceType==null ) {  
  38.         sourceType='MbeansDescriptorsDigesterSource';  
  39.     }  
  40.     ModelerSource ds=getModelerSource(sourceType);  
  41.     List<ObjectName> mbeans =  
  42.         ds.loadDescriptors(this, type, inputsource);  
  43.   
  44.     return mbeans;  
  45. }  
public List<ObjectName> load( String sourceType, Object source, String param) throws Exception { if( log.isTraceEnabled()) { log.trace('load ' source ); } String location=null; String type=null; Object inputsource=null; if( source instanceof URL ) { URL url=(URL)source; location=url.toString(); type=param; inputsource=url.openStream(); if( sourceType == null ) { sourceType = sourceTypeFromExt(location); } } else if( source instanceof File ) { location=((File)source).getAbsolutePath(); inputsource=new FileInputStream((File)source); type=param; if( sourceType == null ) { sourceType = sourceTypeFromExt(location); } } else if( source instanceof InputStream ) { type=param; inputsource=source; } else if( source instanceof Class<?> ) { location=((Class<?>)source).getName(); type=param; inputsource=source; if( sourceType== null ) { sourceType='MbeansDescriptorsIntrospectionSource'; } } if( sourceType==null ) { sourceType='MbeansDescriptorsDigesterSource'; } ModelerSource ds=getModelerSource(sourceType); List<ObjectName> mbeans = ds.loadDescriptors(this, type, inputsource); return mbeans; }
第10到35行说穿是是为该方法适配多种数据源类型给inputsource变量赋上一个输入流。第40行会根据sourceType构造一个ModelerSource对象:
Java代码  
  1. private ModelerSource getModelerSource( String type )  
  2.         throws Exception  
  3. {  
  4.     if( type==null ) type='MbeansDescriptorsDigesterSource';  
  5.     if( type.indexOf( '.') < 0 ) {  
  6.         type='org.apache.tomcat.util.modeler.modules.'   type;  
  7.     }  
  8.   
  9.     Class<?> c = Class.forName(type);  
  10.     ModelerSource ds=(ModelerSource)c.newInstance();  
  11.     return ds;  
  12. }  
private ModelerSource getModelerSource( String type ) throws Exception { if( type==null ) type='MbeansDescriptorsDigesterSource'; if( type.indexOf( '.') < 0 ) { type='org.apache.tomcat.util.modeler.modules.' type; } Class<?> c = Class.forName(type); ModelerSource ds=(ModelerSource)c.newInstance(); return ds; }

上面看到sourceType传入的值是'MbeansDescriptorsDigesterSource'。所以getModelerSource方法最后返回的是org.apache.tomcat.util.modeler.modules.MbeansDescriptorsDigesterSource类的一个实例。

最后执行该ModelerSource对象的loadDescriptors(this, type, inputsource) 方法,因为该方法是一个抽象方法,所以这里实际执行的org.apache.tomcat.util.modeler.modules.MbeansDescriptorsDigesterSource类的loadDescriptors方法:

Java代码  
  1. @Override  
  2. public List<ObjectName> loadDescriptors( Registry registry, String type,  
  3.         Object source) throws Exception {  
  4.     setRegistry(registry);  
  5.     setType(type);  
  6.     setSource(source);  
  7.     execute();  
  8.     return mbeans;  
  9. }  
@Override public List<ObjectName> loadDescriptors( Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; }
前三个set方法毋庸多言,关键是最后的execute方法:
Java代码  
  1. public void execute() throws Exception {  
  2.     if (registry == null) {  
  3.         registry = Registry.getRegistry(nullnull);  
  4.     }  
  5.   
  6.     InputStream stream = (InputStream) source;  
  7.   
  8.     if (digester == null) {  
  9.         digester = createDigester();  
  10.     }  
  11.     ArrayList<ManagedBean> loadedMbeans = new ArrayList<ManagedBean>();  
  12.       
  13.     synchronized (digester) {  
  14.           
  15.         // Process the input file to configure our registry  
  16.         try {  
  17.             // Push our registry object onto the stack  
  18.             digester.push(loadedMbeans);  
  19.             digester.parse(stream);  
  20.         } catch (Exception e) {  
  21.             log.error('Error digesting Registry data', e);  
  22.             throw e;  
  23.         } finally {  
  24.             digester.reset();  
  25.         }  
  26.       
  27.     }  
  28.     Iterator<ManagedBean> iter = loadedMbeans.iterator();  
  29.     while (iter.hasNext()) {  
  30.         registry.addManagedBean(iter.next());  
  31.     }  
  32. }  
public void execute() throws Exception { if (registry == null) { registry = Registry.getRegistry(null, null); } InputStream stream = (InputStream) source; if (digester == null) { digester = createDigester(); } ArrayList<ManagedBean> loadedMbeans = new ArrayList<ManagedBean>(); synchronized (digester) { // Process the input file to configure our registry try { // Push our registry object onto the stack digester.push(loadedMbeans); digester.parse(stream); } catch (Exception e) { log.error('Error digesting Registry data', e); throw e; } finally { digester.reset(); } } Iterator<ManagedBean> iter = loadedMbeans.iterator(); while (iter.hasNext()) { registry.addManagedBean(iter.next()); } }}
在第3行又看到了前面提到的Registry.getRegistry(null, null)方法,这里就是获取Registry的静态成员的引用。这段方法作用就是对source进行一次Digester解析,如果还不了解Digester解析,可以看看之前Tomcat源码分析的一篇文章:Tomcat7启动分析(三)Digester的使用。注意第18行digester的顶层对象是loadedMbeans,重点看下第9行createDigester()方法的调用:
Java代码  
  1.    protected static Digester createDigester() {  
  2.   
  3.        Digester digester = new Digester();  
  4.        digester.setNamespaceAware(false);  
  5.        digester.setValidating(false);  
  6.        URL url = Registry.getRegistry(nullnull).getClass().getResource  
  7.            ('/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd');  
  8.        digester.register  
  9.            ('-//Apache Software Foundation//DTD Model MBeans Configuration File',  
  10.                url.toString());  
  11.          
  12.        // Configure the parsing rules  
  13.        digester.addObjectCreate  
  14.            ('mbeans-descriptors/mbean',  
  15.            'org.apache.tomcat.util.modeler.ManagedBean');  
  16.        digester.addSetProperties  
  17.            ('mbeans-descriptors/mbean');  
  18.        digester.addSetNext  
  19.            ('mbeans-descriptors/mbean',  
  20.                'add',  
  21.            'java.lang.Object');  
  22.          
  23.        digester.addObjectCreate  
  24.            ('mbeans-descriptors/mbean/attribute',  
  25.            'org.apache.tomcat.util.modeler.AttributeInfo');  
  26.        digester.addSetProperties  
  27.            ('mbeans-descriptors/mbean/attribute');  
  28.        digester.addSetNext  
  29.            ('mbeans-descriptors/mbean/attribute',  
  30.                'addAttribute',  
  31.            'org.apache.tomcat.util.modeler.AttributeInfo');  
  32.               
  33. ......  
  34.          
  35.        return digester;  
  36.    }  
protected static Digester createDigester() { Digester digester = new Digester(); digester.setNamespaceAware(false); digester.setValidating(false); URL url = Registry.getRegistry(null, null).getClass().getResource ('/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd'); digester.register ('-//Apache Software Foundation//DTD Model MBeans Configuration File', url.toString()); // Configure the parsing rules digester.addObjectCreate ('mbeans-descriptors/mbean', 'org.apache.tomcat.util.modeler.ManagedBean'); digester.addSetProperties ('mbeans-descriptors/mbean'); digester.addSetNext ('mbeans-descriptors/mbean', 'add', 'java.lang.Object'); digester.addObjectCreate ('mbeans-descriptors/mbean/attribute', 'org.apache.tomcat.util.modeler.AttributeInfo'); digester.addSetProperties ('mbeans-descriptors/mbean/attribute'); digester.addSetNext ('mbeans-descriptors/mbean/attribute', 'addAttribute', 'org.apache.tomcat.util.modeler.AttributeInfo'); ...... return digester; }

上面这段代码其实很长,但绝大部分都是模板代码,理解几句的含义后面代码都很相似。这就是一个xml文件的解析,第13到15行是值在碰到xml文件的mbeans-descriptors节点的子节点mbean时构造一个org.apache.tomcat.util.modeler.ManagedBean对象,第16到17行是读取该节点属性值填充到ManagedBean对象的pojo属性中,第18到21行以ManagedBean对象为入参调用上一段代码分析提到的loadedMbeans对象的add方法。类似的,第23到31行是指在碰到mbeans-descriptors/mbean/attribute节点时构造org.apache.tomcat.util.modeler.AttributeInfo对象,填充pojo属性,并调用父节点构造的对象(即ManagedBean对象)的addAttribute方法。其它代码类似,不再赘述。

 

接回到上面MbeansDescriptorsDigesterSource类的execute方法第28到31行,在Digester解析完成之后迭代loadedMbeans对象,并调用registry.addManagedBean方法将这些ManagedBean添加到registry中。这样,一次registry.loadDescriptors('org.apache.catalina.connector', cl)调用就会加载该包路径下相对应的ManagedBean对象到Registry类的成员变量中。

 

下面的时序图列出从GlobalResourcesLifecycleListener类加载其静态成员变量registry到Registry类加载完相应包所对应的ManagedBean的关键方法调用过程:



2.注册MBean实例

2.1.查找ManagedBean

上面说的是一个ManagedBean的加载过程,但它不是一个MBean,可以把它看作一个描述MBean的配置信息的对象,以前面提到的org.apache.catalina.connector为例,在Tomcat7的默认配置启动后实际上有两个Connector实例,因为在server.xml中配置了两条connector节点:

Xml代码  
  1. <Connector port='8080' protocol='HTTP/1.1'  
  2.            connectionTimeout='20000'  
  3.            redirectPort='8443' />  
  4.   
  5.   
  6. <Connector port='8009' protocol='AJP/1.3' redirectPort='8443' />  
<Connector port='8080' protocol='HTTP/1.1' connectionTimeout='20000' redirectPort='8443' />... <Connector port='8009' protocol='AJP/1.3' redirectPort='8443' />

所对应jconsole中会看到两个相应的MBean对象:


但ManageBean实际只是加载了一次。了解了ManagedBean与MBean的对应关系,接下来看看一个MBean是怎么注册到JVM中的。

 

看过前面Tomcat启动分析的朋友知道容器各组件在启动过程中会相继调用它们的initInternal()、startInternal()两个方法,还是以上面提到的Connector组件为例,Tomcat启动时解析server.xml文件过程中碰到Connector节点配置会构造org.apache.catalina.connector.Connector对象并调用它的initInternal方法:

Java代码  
  1. @Override  
  2. protected void initInternal() throws LifecycleException {  
  3.   
  4.     super.initInternal();  
@Override protected void initInternal() throws LifecycleException { super.initInternal();...
在这个方法的开始会调用它的父类org.apache.catalina.util.LifecycleMBeanBase的initInternal方法:
Java代码  
  1. private ObjectName oname = null;  
  2. protected MBeanServer mserver = null;  
  3.   
  4. /** 
  5.  * Sub-classes wishing to perform additional initialization should override 
  6.  * this method, ensuring that super.initInternal() is the first call in the 
  7.  * overriding method. 
  8.  */  
  9. @Override  
  10. protected void initInternal() throws LifecycleException {  
  11.       
  12.     // If oname is not null then registration has already happened via  
  13.     // preRegister().  
  14.     if (oname == null) {  
  15.         mserver = Registry.getRegistry(nullnull).getMBeanServer();  
  16.           
  17.         oname = register(this, getObjectNameKeyProperties());  
  18.     }  
  19. }  
private ObjectName oname = null; protected MBeanServer mserver = null; /** * Sub-classes wishing to perform additional initialization should override * this method, ensuring that super.initInternal() is the first call in the * overriding method. */ @Override protected void initInternal() throws LifecycleException { // If oname is not null then registration has already happened via // preRegister(). if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } }
先获取MBeanServer的实例,接着调用内部的register方法,将当前对象注册到MBeanServer中,看下register方法:
Java代码  
  1. protected final ObjectName register(Object obj,  
  2.         String objectNameKeyProperties) {  
  3.       
  4.     // Construct an object name with the right domain  
  5.     StringBuilder name = new StringBuilder(getDomain());  
  6.     name.append(':');  
  7.     name.append(objectNameKeyProperties);  
  8.   
  9.     ObjectName on = null;  
  10.   
  11.     try {  
  12.         on = new ObjectName(name.toString());  
  13.           
  14.         Registry.getRegistry(nullnull).registerComponent(obj, on, null);  
  15.     } catch (MalformedObjectNameException e) {  
  16.         log.warn(sm.getString('lifecycleMBeanBase.registerFail', obj, name),  
  17.                 e);  
  18.     } catch (Exception e) {  
  19.         log.warn(sm.getString('lifecycleMBeanBase.registerFail', obj, name),  
  20.                 e);  
  21.     }  
  22.   
  23.     return on;  
  24. }  
protected final ObjectName register(Object obj, String objectNameKeyProperties) { // Construct an object name with the right domain StringBuilder name = new StringBuilder(getDomain()); name.append(':'); name.append(objectNameKeyProperties); ObjectName on = null; try { on = new ObjectName(name.toString()); Registry.getRegistry(null, null).registerComponent(obj, on, null); } catch (MalformedObjectNameException e) { log.warn(sm.getString('lifecycleMBeanBase.registerFail', obj, name), e); } catch (Exception e) { log.warn(sm.getString('lifecycleMBeanBase.registerFail', obj, name), e); } return on; }
重点是第14行调用Registry类的registerComponent方法来注册:
Java代码  
  1. public void registerComponent(Object bean, ObjectName oname, String type)  
  2.        throws Exception  
  3. {  
  4.     if( log.isDebugEnabled() ) {  
  5.         log.debug( 'Managed= '  oname);  
  6.     }  
  7.   
  8.     if( bean ==null ) {  
  9.         log.error('Null component '   oname );  
  10.         return;  
  11.     }  
  12.   
  13.     try {  
  14.         if( type==null ) {  
  15.             type=bean.getClass().getName();  
  16.         }  
  17.   
  18.         ManagedBean managed = findManagedBean(bean.getClass(), type);  
  19.   
  20.         // The real mbean is created and registered  
  21.         DynamicMBean mbean = managed.createMBean(bean);  
  22.   
  23.         if(  getMBeanServer().isRegistered( oname )) {  
  24.             if( log.isDebugEnabled()) {  
  25.                 log.debug('Unregistering existing component '   oname );  
  26.             }  
  27.             getMBeanServer().unregisterMBean( oname );  
  28.         }  
  29.   
  30.         getMBeanServer().registerMBean( mbean, oname);  
  31.     } catch( Exception ex) {  
  32.         log.error('Error registering '   oname, ex );  
  33.         throw ex;  
  34.     }  
  35. }  
public void registerComponent(Object bean, ObjectName oname, String type) throws Exception { if( log.isDebugEnabled() ) { log.debug( 'Managed= ' oname); } if( bean ==null ) { log.error('Null component ' oname ); return; } try { if( type==null ) { type=bean.getClass().getName(); } ManagedBean managed = findManagedBean(bean.getClass(), type); // The real mbean is created and registered DynamicMBean mbean = managed.createMBean(bean); if( getMBeanServer().isRegistered( oname )) { if( log.isDebugEnabled()) { log.debug('Unregistering existing component ' oname ); } getMBeanServer().unregisterMBean( oname ); } getMBeanServer().registerMBean( mbean, oname); } catch( Exception ex) { log.error('Error registering ' oname, ex ); throw ex; } }
在第18行根据当前要注册的对象(即Connector对象)的类型查找ManagedBean,沿着这个方法追会发现依次调用了一堆同名的findManagedBean方法,一直到findManagedBean(String name):
Java代码  
  1. public ManagedBean findManagedBean(String name) {  
  2.     // XXX Group ?? Use Group   Type  
  3.     ManagedBean mb = descriptors.get(name);  
  4.     if( mb==null )  
  5.         mb = descriptorsByClass.get(name);  
  6.     return mb;  
  7. }  
public ManagedBean findManagedBean(String name) { // XXX Group ?? Use Group Type ManagedBean mb = descriptors.get(name); if( mb==null ) mb = descriptorsByClass.get(name); return mb; }
这段代码意思是依次从Registry类的静态成员变量descriptors、descriptorsByClass中查找相应ManagedBean。那这两个HashMap是什么时候put值进去的呢?答案就在上一部分分析的最后加载ManagedBean时最终调用Registry类的addManagedBean方法:
Java代码  
  1. public void addManagedBean(ManagedBean bean) {  
  2.     // XXX Use group   name  
  3.     descriptors.put(bean.getName(), bean);  
  4.     if( bean.getType() != null ) {  
  5.         descriptorsByClass.put( bean.getType(), bean );  
  6.     }  
  7. }  
public void addManagedBean(ManagedBean bean) { // XXX Use group name descriptors.put(bean.getName(), bean); if( bean.getType() != null ) { descriptorsByClass.put( bean.getType(), bean ); } }
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[JMX一步步来] 5、用Apache的commons
Java中的JavaCore/HeapDump文件及其分析方法 – 码农网
关于JMX的示例
Dubbo安装部署
Jenkins与Docker的自动化CI/CD实战
tomcat 源码入门
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服