tomcat阅读第六篇(tomcat jmx管理)
中秋归来,这篇分析tomcat关于jmx的部分,tomcat用的是DynamicMBean,不熟悉JMX的同学可以网上看下,上篇文章分析了tomcat的Catalina类,了解到Catalina会调用StandardServer,现在看下StandardServer的继承关系
这篇文章重点看LifecycleMBeanBase,他是跟JMX相关的部分,先看下接口Lifecycle,看名字可以知道是跟生命周期相关的接口,下面方法是跟添加Listener相关方法
public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener);
下面方法是跟生命周期相关的回调方法,init,start,stop ,destroy
public void init() throws LifecycleException; public void start() throws LifecycleException; public void stop() throws LifecycleException; public void destroy() throws LifecycleException;
LifecycleBase类是简单对Lifecycle接口的实现。
现在重点看下LifecycleMBeanBase类,重点看initInternal方法,destroyInternal方法,domain和ObjectName属性,这两个属性跟JMX直接相关,先看下getDomain方法
public final String getDomain() { if (domain == null) { //调用抽象方法 getDomainInternal,getDomainInternal方法需要JMX管理的类覆盖 domain = getDomainInternal(); } if (domain == null) { //默认用DEFAULT_MBEAN_DOMAIN domain = Globals.DEFAULT_MBEAN_DOMAIN; } return domain; } ObjectName属性相关的方法initInternal,destroyInternal protected void initInternal() throws LifecycleException { if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); //注册得到ObjectName oname = register(this, getObjectNameKeyProperties()); } } protected void destroyInternal() throws LifecycleException { //注销ObjectName unregister(oname); }
在看下register方法, unregister方法注销MBean
protected final ObjectName register(Object obj, String objectNameKeyProperties) { StringBuilder name = new StringBuilder(getDomain()); name.append(':'); name.append(objectNameKeyProperties); ObjectName on = null; try { // 实例化ObjectName,getDomain,objectNameKeyProperties需要之类覆写,有了ObjectName就可以用来在Server上注册MBean 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; }
上面的方法可以看到Registry类,tomcat跟JMX相关的主要类,看Registry类方法之前先看类GlobalResourcesLifecycleListener、MBeanUtils。GlobalResourcesLifecycleListener类
上图可以看到server.xml配置,再看Catalina类的createDigester方法,上篇分析可以知道Catalina类的createDigester方法内容是解析server.xml的配置
可以知道会调用Server上的addLifecycleListener方法传入LifecycleListener,主要看GlobalResourcesLifecycleListener类的属性
protected static final Registry registry = MBeanUtils.createRegistry();
可以看到类MBeanUtils,现在看createRegistry方法,createRegistry方法会调用Rigestry的loadDescriptors方法,加载org.apache.catalina下一系列的MBean描述, loadDescriptors方法会去相对应的包下加载mbeans-descriptors.xml配置,loadDescriptors方法调用load方法去实际加载MBean描述,
方法调用链loadDescriptors->load("MbeansDescriptorsDigesterSource", dURL, null),Load方法根据传入的参数获取ModelerSource类,调用ModelerSource类的loadDescriptors(Registry, type, inputsource)方法,ModelerSource继承关系。
这条线会调用MbeansDescriptorsDigesterSource的loadDescriptors方法加载MBean描述,我们可以看到createDigester方法,可以熟悉的看到跟Catalina类相似的代码,Digester那篇分析过,现在看下loadDescriptors方法-> execute方法
public void execute() throws Exception { if (registry == null) { registry = Registry.getRegistry(null, null); } InputStream stream = (InputStream) source; ArrayList<ManagedBean> loadedMbeans = new ArrayList<>(); synchronized(dLock) { if (digester == null) { //配置解析包下的mbeans-descriptors.xml文件 digester = createDigester(); } try { //push loadedMbeans digester.push(loadedMbeans); //开始解析 digester.parse(stream); } catch (Exception e) { log.error("Error digesting Registry data", e); throw e; } finally { digester.reset(); } } //调用registry.addManagedBean,传入ManageBean Iterator<ManagedBean> iter = loadedMbeans.iterator(); while (iter.hasNext()) { registry.addManagedBean(iter.next()); } }
现在我们简单的看下createDigester和对应的mbeans-descriptors.xml,以org\apache\catalina\mbeans-descriptors.xml为例子,自己可以打开看
//解析到mbeans-descriptors/mbean,实例化ManagedBean类 digester.addObjectCreate ("mbeans-descriptors/mbean", "org.apache.tomcat.util.modeler.ManagedBean"); //设置mbeans-descriptors/mbean的attribute给ManagedBean类 digester.addSetProperties ("mbeans-descriptors/mbean"); //调用loadedMbeans的add方法传入ManagedBean digester.addSetNext ("mbeans-descriptors/mbean", "add", "java.lang.Object"); //解析到mbeans-descriptors/mbean/attribute,实例化类AttributeInfo digester.addObjectCreate ("mbeans-descriptors/mbean/attribute", "org.apache.tomcat.util.modeler.AttributeInfo"); //设置mbeans-descriptors/mbean/attribute的attribute给AttributeInfo类 digester.addSetProperties digester.addSetProperties ("mbeans-descriptors/mbean/attribute"); digester.addSetNext ("mbeans-descriptors/mbean/attribute", "addAttribute", "org.apache.tomcat.util.modeler.AttributeInfo"); 以下类推 …………………………………
总之parse最后的结果是,Registry类加载了mbeans-descriptors.xml配置下的ManagedBean。
现在在看MbeansDescriptorsIntrospectionSource类,loadDescriptors->execute->createManagedBean方法,根据Class类创建ManagedBean,add进Registry。
现在回头看Registry类的registerComponent和unregisterComponent方法
主要看registerComponent方法,registerComponent方法findManagedBean ,找到对应的ManagedBean ,然后ManagedBean.createMBean ,getMBeanServer().registerMBean( mbean, oname)。
总结:跟tomcat JMX相关的主要是Registry,GlobalResourcesLifecycleListener->Registry.createRegistry->解析包下的mbeans-descriptors.xml配置,Registry.addManageBean,
当initInternal 方法register的时候,会获取ManageBean,当找不到ManageBean的时候,会通过MbeansDescriptorsIntrospectionSource 来创建ManageBean,然后调用ManageBean. createMBean,注册DynamicMBean。