jmx简介

2012-09-13 10:57:56
《深入剖析Tomcat 》第20章 基于JMX的管理
浏览(2309)|评论(1)  交流分类:Java|笔记分类: tomcat

         19章中讨论了manager应用,它展示了如何使用实现了ContainerServlet接口的ManagerServlet类来访问catalina的内部类。本章将说明如何使用jmx管理tomcat。本章会先简要介绍jmx,然后讨论Common Modeler库,tomcat使用该库对Managed Bean进行管理。

20.1  jmx简介

         既然ContainerServlet已经可以管理tomcat,为啥要用jmx?因为jmx更灵活。许多基于服务器的应用程序,如tomcat,jboss,jonas,geromino等,使用jmx管理其资源。

         jmx规范(书中指规范1.2.1版本)定义了管理java对象的公开标准。例如,tomcat4和5使用jmx来启动servlet容器中的各种对象(如server,host,context,valve等),这样更灵活,更易于管理。tomcat的开发者也编写了admin应用来管理其他web应用。

         由基于jmx的管理应用程序管理的java对象成为jmx托管资源。事实上,一个jmx托管资源也可以是一个应用程序,一个service实现,一个设备,一个用户等等。jmx托管资源由java编写,提供了相应的包装。

         要想将一个java对象转换为jmx托管资源,你需要另外创建一个名为MBean的对象。org.apache.catalina.mbeans包下,包含有一些MBean,例如,ConnectorMBean,StandardEngineMBean,StandardHostMBean,StandardContextMBean。由名字可猜想,ConnectorMBean用于管理connector,StandardContextMBean用于管理org.apache.catalina.core.StandardContext实例。你也可以编写自己的MBean管理你自己的java对象。

         MBean类暴露出了它所管理的java对象的属性和方法。管理应用程序本身并不直接访问它所管理的java对象,因此,你可以选择性的暴露出需要的属性和方法。

         拥有的MBean类后,你将它实例化,并将其注册到MBean服务器中。MBean服务器是一个应用中所有MBean注册的中心地。管理应用程序通过MBean服务器访问MBean。若是将jmx和servlet开发相比较的话,管理应用程序则等同于web浏览器,MBean服务器等同于servlet容器,它提供了托管资源的访问。MBean则等同于servlet/jsp。web浏览器并不直接访问servlet/jsp,而是通过servlet容器来访问,管理应用程序也是通过MBean服务器访问MBean的。

         有四种类型MBean:standard,dynamic,open,model。standard Mbean是四种类型中最容易编写的,但灵活性最差。这里重点讨论tomcat所使用的model MBean。standard MBean会用来写一个小例子来展示如何使用jmx。

         从结构上,jmx分为三个层次,表现层,代理层,分布式服务层。MBean服务器位于代理层,MBean位于表现层。而分布式服务层将在以后的jmx的版本中涉及。

         jmx规范的表现层定义了编写jmx托管资源的标准方法,例如定义了如何编写一个MBean。代理层定义了创建代理的规范。jmx的代理包括一个MBean服务器,用于处理MBean服务。一般情况下,代理和MBean是位于同一个jvm中的。jmx规范中有一个参考实现,因此,你不必自己实现MBean服务器,参考实现给出了实现MBean服务器的方法。

         jmx的参考实现可以从这里下载:

http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html

20.2  jmx api

         jmx的参考实现中包含了一个核心java库,位于javax.management包和其他一些包下(用于jmx的其他方方面)。

20.2.1  MBeanServer

         javax.management.MBeanServer接口表示一个MBean服务器。要创建一个MBean服务器,只需要调用javax.management.MBeanServerFactory类的createMBean即可。要将一个MBean注册到MBean服务器中,可以调用MBeanServer的registerMBean方法。下面是registerMBean方法的签名:

 

java代码:
  1. public ObjectInstance registerMBean(java.lang.Object object,   
  2.    ObjectName name) throws InstanceAlreadyExistsException,   
  3.   MBeanRegistrationException, NotCompliantMBeanException  

         要注册一个MBean,需要传入一个MBean对象,和一个ObjectName对象。一个ObjectName实例类似于HashMap中的key,可以唯一标识一个MBean。registerMBean方法返回一个ObjectInstance实例。javax.management.ObjectInstance类包装了一个MBean和它的类名。

         MBeanServer接口提供了两个方法queryNames和queryMBeans用于获取某个MBean或符合某个匹配模式的一组MBean。queryNames方法返回java.util.Set对象,包含了匹配某个模式的一组MBean的名字。方法签名为:

 

java代码:
  1. public java.util.Set queryNames(ObjectName name, QueryExp query)  

         参数query执行过滤表达式。若参数name为null,或者没有域,而且指定了key属性,则会返回所有已经注册的MBean的ObjectName。若query为null,则不会进行过滤。

         queryMBeans方法与queryNames方法类似,它返回的也是java.util.Set,包含了针对所要查找的MBean的ObjectInstance。方法签名为:

 

java代码:
  1. public java.util.Set queryMBeans(ObjectName name, QueryExp query)  

         如果你想要获得MBean的对象名称,你可以操作托管资源的属性或者调用MBean中暴露出的方法。通过调用MBeanServer的invoke方法,你可以调用已注册的MBean所暴露出的任何方法。MBeanServer的getAttribute和setAttribute方法用于对已注册的MBean的属性进行操作。

20.2.2  ObjectName

         MBean注册于MBeanServer,类似于HashMap中的key,每个MBean通过一个对象名称进行唯一标识。对象名称由javax.management.ObjectName类表示。一个ObjectName包含两部分,一个域(domain)和一个key/value集合。domain是一个字符串,可以为空。在一个对象名称中,domain后面跟着一个冒号和一个或多个key/value对。key是一个非空字符串,且不能包含下列字符:等号,逗号,冒号,问号或星号。一个对象名称中key是唯一的。      key与value通过等号连接,key/value对之间由逗号分隔。例如:

 

java代码:
  1. myDomain:type=Car,color=blue  

         在MBeanServer中查找MBean时,ObjectName实例也可以表示属性模式。作为匹配模式的ObjectName可以在其domain和key/value中使用通配符。一个作为匹配模式的ObjectName可以有0个或多个key。

20.3  Standard MBeans

         standard MBean是最简单的MBean,要想通过standard MBean管理java对象,需要完成一些步骤。这里假设你要管理的java对象的类名为Car。步骤如下:

         (1)创建一个接口,该接口名规范为:你的java对象类名+MBean。例如,你想要管理的java对象的类名为Car,则需要创建的接口名为CarMBean;

         (2)修改你的java类,让其实现CarMBean接口;

         (3)创建一个代理,该代理中必须包含有MBeanServer;

         (4)为你的MBean创建ObjectName实例;

         (5)实例化MBeanServer;

         (6)将MBean注册到MBeanServer中。

 

         standard MBean很容易编写,使用MBean需要修改你的java类(如需要实现创建的MBen接口),在某些工程里,这是不可行的。MBean的其他类型则不需要这样的限制。

         下面代码完成Car的MBean的创建:

         你需要在接口中声明,你需要暴露出哪些需要操作的属性和方法。在本例中,CarMBean接口暴露出了Car的所有方法。接下来,需要定义一个代理,StandardAgent,用来创建MBean,管理Car对象。实现代码如下:

StandardAgent类是代理层,负责实例化MBeanServer,使用MBeanServer对象注册MBean:


java代码:
  1. public StandardAgent() {   
  2.         mBeanServer = MBeanServerFactory.createMBeanServer();   
  3.     }  

         createMBeanServer方法返回一个jmx参考实现的默认的MBeanServer对象。你有兴趣的话,可以自己实现一个MBeanServer。

         createObjectName方法返回一个ObjectName对象。createStandardMBean方法调用MBeanServer类的createMBean方法,createMBean方法接收一个托管资源的类名和一个ObjectName实例来创建托管资源的MBean对象。createMBean方法还会将创建的MBean注册到MBeanServer中。由于standard MBean的遵循了固定的命名约定,因此在createMBean方法中你不需要提供MBean的类型。

         StandardAgent的main方法会先创建一个StandardAgent对象,调用getMBeanServer方法获取一个MBeanServer对象引用:

 

java代码:
  1. StandardAgent agent = new StandardAgent();   
  2.    MBeanServer mBeanServer = agent.getMBeanServer();  

         然后为CarMBean创建ObejctName,MBeanServer的默认domain被用于ObejctName的domain,ObejctName的key/value使用了type作为key,托管资源的全类名作为value:

 

java代码:
  1. String domain = mBeanServer.getDefaultDomain();   
  2.     String managedResourceClassName = "ex20.pyrmont.standardmbeantest.Car";   
  3.     ObjectName objectName = agent.createObjectName(domain + ":type=" + managedResourceClassName);  

然后,main方法调用createStandardBean方法,传入ObjectName对象和托管资源的类名:

 

java代码:
  1. agent.createStandardBean(objectName, managedResourceClassName);  

         接下来,main方法通过CarMBean来管理Car对象。它首先创建了一个Attribute对象colorAttribute来表示Car的color属性,并设置值为blue。然后,它调用setAttribute方法,传入objectName和colorAttribute。最后又通过MBeanServer的invoke方法调用了Car的drive方法。

 

java代码:
  1. // manage MBean   
  2.     try {   
  3.       Attribute colorAttribute = new Attribute("Color","blue");   
  4.       mBeanServer.setAttribute(objectName, colorAttribute);   
  5.       System.out.println(mBeanServer.getAttribute(objectName, "Color"));   
  6.       mBeanServer.invoke(objectName,"drive",null,null);   
  7.     }  

20.4  Model MBeans

         相比于standard MBean,model MBean更具灵活性。在编码上,model MBean难度更大一下,但你也不再需要修改要管理的java类了(在standard MBean中,你必须修改要管理的java类,使其实现MBean接口)。

         使用model MBean,你不在需要创建MBean接口,相反,javax.management.modelmbean.ModelMBean接口就是用了表示一个model MBean,你只需要实现这个接口。jmx也提供了对这个接口的默认实现,javax.management.modelmbean.RequiredModelMBean。你只需要实例化这个类或其子类。

         注意,使用ModelMBean接口的其他实现也是可以的。例如,在下面章节讨论的Commons Modeler库就提供了自定义的实现。

         使用model MBean的难点在于告诉ModelMBean托管资源的哪些属性和方法可以暴露给代理层。这里,你需要创建一个javax.management.modelmbean.ModelMBeanInfo对象。ModelMBeanInfo对象描述了要暴露给代理层的构造器,属性,操作和监听器。创建ModelMBeanInfo对象的工作单调乏味,但是一旦拥有,别无所求,只要将其与ModelMBean相关联即可。

         使用RequiredModelMBean作为ModelMBean的实现,有两个方法将ModelMBean和ModelMBeanInfo相关联:

         (1)在RequiredModelMBean的构造函数中传入ModelMBeanInfo对象;

         (2)调用RequiredModelMBean对象的setModelMBeanInfo方法,传入ModelMBeanInfo对象。

         在创建了ModelMBean之后,必须要调用其setManagedResource方法与托管资源相关联,该方法的签名如下:

 

java代码:
  1. public void setManagedResource(java.lang.Object managedResource,   
  2.    java.lang.String managedResourceType) throws MBeanException,   
  3.    RuntimeOperationsException, InstanceNotFoundException,   
  4.    InvalidTargetObjectTypeException  

         参数managedResourceType的值可以是下面的值之一,ObjectReference,Handle,IOR,EJBHandle或RMIReference。当前只支持ObjectReference。

         当然,你还需要创建ObjectName,并将MBean注册到MBeanServer中。

20.4.1  MBeanInfo与ModelMBeanInfo

 

java代码:
  1. javax.management.mbean.ModelMBeanInfo接口描述了要通过ModelMBean暴露给代理层的构造器,属性,操作和监听器。构造器由javax.management.modelmbean.ModelMBeanConstructorInfo表示。属性由javax.management.modelmbean.ModelMBeanAttributeInfo表示。操作由javax.management.modelmbean.ModelMBeanOperationInfo表示,监听器由javax.management.modelmbean.ModelMBeanNotificationInfo表示。本章只讨论属性和操作。  
  2. jmx提供了javax.management.modelmbean.ModelMBeanInfoSupport的默认实现ModelMBeanInfo。下面是ModelMBeanInfoSupport的构造器:  

 

java代码:
  1. public ModelMBeanInfoSupport(java.lang.String className,   
  2.    java.lang.String description, ModelMBeanAttributeInfo[] attributes,   
  3.   ModelMBeanConstructorInfo[] constructors,   
  4.   ModelMBeanOperationInfo[] operations,   
  5.   ModelMBeanNotificationInfo[] notifications)  

ModelMBeanAttributeInfo的构造器如下:

 

java代码:
  1. public ModelMBeanAttributeInfo(java.lang.String name,   
  2.    java.lang.String type, java.lang.String description,   
  3.    boolean isReadable, boolean isWritable,   
  4.    boolean isIs, Descriptor descriptor)   
  5.    throws RuntimeOperationsException  

下面是参数列表说明:

l         name,属性名;

l         type,属性的类型;

l         description,属性描述说明;

l         isReadable,若属性有getter方法,则为true,否则为false;

l         isWritable,参考isReadable;

l         isIs,参考isReadable;

l         descriptor,Descriptor对象,包含了Attribute对象的元数据,若置为null,则会创建默认的descriptor。

 

ModelMBeanOperationInfo的构造器如下:

 

java代码:
  1. public ModelMBeanOperationInfo(java.lang.String name,   
  2.    java.lang.String description, MBeanParameterInfo[] signature,   
  3.    java.lang.String type, int impact, Descriptor)   
  4.    throws RuntimeOperationsException  

下面是参数列表说明:

l         name,方法名;

l         description,方法描述;

l         signature,MBeanParameterInfo数组,保存方法的参数;

l         type,方法返回值的类型;

l         impact,方法的影响(大概是这个意思),可选值如下,INFO,ACTION,ACTION_INFO,UNKNOWN;

l         descriptor,Descriptor对象,包含了MBeanOperationInfo对象的元数据,若置为null,则会创建默认的descriptor。

 

20.4.2  ModelMBean实例

         使用model MBean管理Car对象,你不需要再创建MBean接口,只需要实例化RequiredMBean类。下面的代码提供了代理层ModelAgent,用于创建MBean来管理Car对象。ModelAgent类实现代码如下:

         如代码所示,使用model MBean,你需要多做一些工作,尤其是要声明所有要暴露出的属性,方法。但灵活性更好。下一节将介绍Commons Modeler库,该库可以帮助你更快的编写model MBean。

20.5  Commons Modeler

         Commons Modeler库是apache Jakarta项目的一部分,目的是使编写model MBeans更加方便。最打的帮助是你不需要在写代码创建ModelMBeanInfo对象了。

         回忆前面的章节,创建RequiredModelMBean对象时,你需要传入RequiredModelMBean的构造函数,创建一个ModelMBeanInfo对象:

 

java代码:
  1. ModelMBeanInfo mBeanInfo = createModelMBeanInfo(objectName, mbeanName);   
  2.    RequiredModelMBean modelMBean = null;   
  3.     try {   
  4.         modelMBean = new RequiredModelMBean(mBeanInfo);   
  5.     }   

         ModelMBeanInfo描述了要暴露出的属性和方法,实现createModelMBeanInfo方法是枯燥的,因为你不得不列出所有要暴露的属性和方法并将它们传给ModelMBeanInfo对象。

而使用Commons Modeler库,你就不再需要创建ModelMBeanInfo对象,对MBean的描述被封装在org.apache.catalina.modeler.ManagedBean对象中。你只需要编写一个简单你的描述文件(xml格式),列出你想要创建的MBean。对每个MBean,你要列出他的全限定名,包括MBean的名字和托管资源的类名,还要写出要暴露出的属性和方法的名称。然后,使用org.apache.commons.modeler.Registry对象读取该xml文件,依照配置创建MBeanServer和所有的ManagedBean。

然后,你就可以调用ManagedBean的createMBean方法创建MBean了。之后的事一切照旧。你需要创建一个ObejctName对象,将MBean注册到MBeanServer中。

         下面,要说明下MBean的描述文件,然后讨论三个比较重要的类Registry,ManagedBean和BaseModelMBean。

         注意,tomcat4中仍然使用了老版本的Modeler,使用一些deprecated的方法。

20.5.1  MBean描述符

         MBean的描述符是是一个xml文件,该文件对有MBeanServer管理的model MBean进行描述。MBean描述符以下面的代码开始:

 

java代码:
  1. <?xml version="1.0"?>   
  2. <!DOCTYPE mbeans-descriptors PUBLIC   
  3.   "-//Apache Software Foundation//DTD Model MBeans Configuration File"   
  4.   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">  

         接下来是根元素:

 

java代码:
  1. <mbeans-descriptors>   
  2. ...   
  3. </mbeans-descriptors>  

         mbeans-descriptors标签中间部分mbean标签,每个mbean标签表示一个model MBean,mbean元素下的元素表示属性,方法,构造器,监听器。

20.5.1.1  mbean

         mbean元素描述了一个model MBean,包含了创建ModelMBeanInfo对象的信息。mbean元素有如下的定义:

 

java代码:
  1. <!ELEMENT mbean (descriptor?, attribute*, constructor*, notification*, operation*)>  

         mbean元素定义了具体的规范,mbean标签下可以有一个可选的descriptor标签,0个或多个attribute标签,constructor标签,notification标签,operation标签。

         mbean标签可以有如下的属性:

l         className,ModelMBean的实现类的全名,若该属性未赋值,则默认使用org.apache.commons.modeler.BaseModelMBean类;

l         description,该model MBean的简单描述;

l         domain,MBeanServer的domain值,由MBeanServer创建的ModelMBean会属于这个domain;

l         group,即“grouping classification”,用来选择MBean相似实现的的组;

l         name,model MBean的唯一标识;

l         type,托管资源实现类的全名。

 

20.5.1.2  attribute

         使用attribute标签描述MBean的属性。attribute标签有一个可选的descriptor元素,descriptor元素有如下可选属性:

l         description,该属性的简单描述;

l         displayName,该属性的显示名称;

l         getMethod,该属性的getter方法;

l         is,一个bool值,指明该bool值是否有getter方法,默认为false;

l         name,属性名;

l         readable,一个bool值,指明该属性是否可读,默认为true;

l         setMethod,该属性的setter方法;

l         type,该属性的Java类的全名;

l         writeable,一个bool值,表明该属性是否有setter方法,默认为true。

 

20.5.1.3  operation

         operation标签描述了mdel MBean中要暴露给管理应用程序的公开方法,可以有0个或多个parameter元素和如下的属性:

l         description,方法的简单描述;

l         impact,指明方法的影响力,可选值为,ACTION (write like),ACTION-INFO (write+read like),INFO(read like)或UNKNOWN;

l         name,方法名;

l         returnType,方法返回值的java类的全名。

 

20.5.1.4  parameter

l         parameter标签描述了传给构造函数或方法的参数。可以有如下属性:

l         description,该参数的简单描述;

l         name,参数名;

l         type,参数的类型(java全类名)。

 

20.5.2  mbean标签实例

         在catalina的mbean-descriptors.xml文件中声明了一系列model MBean,该文件位于org.apache.catalina.mbeans包下,下面的代码是对托管资源StandardServer进行包装的MBean的声明:

 

java代码:
  1. <mbean name="StandardServer" className="org.apache.catalina.mbeans.StandardServerMBean"   
  2.    description="Standard Server Component"    domain="Catalina"  group="Server"   
  3.    type="org.apache.catalina.core.StandardServer">   
  4.    <attribute name="debug"  description="The debugging detail level for this component"  type="int"/>   
  5.    <attribute name="managedResource" description="The managed resource this MBean is associated with"   
  6.      type="java.lang.Object"/>   
  7.    <attribute name="port" description="TCP port for shutdown messages"  type="int"/>   
  8.    <attribute name="shutdown" description="Shutdown password" type="java.lang.String"/>   
  9.    <operation name="store" description="Save current state to server.xml file"  impact="ACTION"   
  10.      returnType="void">   
  11.    </operation>   
  12. </mbean>  

         mbean元素声明了一个model MBean,其唯一标识是StandardServer。该MBean是一个org.apache.catalina.mbeans.StandardServerMBean的对象,负责管理org.apache.catalina.core.StandardServer对象。domain是Catalina,group是Server。

20.5.3  自己编写一个model MBean

         使用Commons Modeler库,需要在mbean元素的className属性中指明自定义的model MBean的全类名。默认情况下,Commons Modeler使用org.apache.commons.modeler.BaseModelMBean类。有以下两种情况,你可能需要对其进行扩展:

l         你需要覆盖托管资源的属性;

l         你需要为托管资源添加属性或方法。

 

20.5.4  注册

         org.apache.commons.modeler.Registry类中有一些方法用于注册MBean,下面是你可以使用该类做的事情:

l         获取一个javax.management.MBeanServer对象(你不在需要调用javax.management.MBeanServerFactory的createMBeanServer方法);

l         使用loadRegistry方法读取描述符文件;

l         创建一个ManagedBean对象,用于创建model MBean。

 

20.5.5  ManagedBean

ManagedBean对象描述了一个model MBean,该类用于取代javax.management.MBeanInfo类。

20.5.6  BaseModelMBean

         org.apache.commons.modeler.BaseModelMBean实现了javax.management.modelmbean.ModelMBean接口,使用这个类,就不需要用javax.management.modelmbean.RequiredModelMBean类了。

         该类用一个比较有用的属性是resource属性。resource表明了该model MBean管理的托管资源对象,resource声明如下:

 

java代码:
  1. protected java.lang.Object resource;  

20.5.7  使用Modeler API

有一个类Car是要管理的, ,现在使用Commons Modeler库,你不再需要在代码中纠结于Car类中众多的属性和方法。你需要将属性和方法写到xml文件中,例如下面的文件:

然后你需要编写一个代理类ModelAgent,代码如下:

20.6  Catalian中的MBean

         正如本章开头所说,Catalina的org.apache.catalina.mbeans包中提供了一系列MBean,这些MBean都直接或间接的继承自org.apache.commons.modeler.BaseModelMBean。本节会讨论tomcat4中几个比较重要的MBean,ClassNameMBean,StandardServerMBean和MBeanFactory。

20.6.1  ClassNameMBean

org.apache.catalina.mbeans.ClassNameMBean类继承自org.apache.commons.modeler.BaseModelMBean。它提供了一个只写的属性className,用于表示托管资源的类名。该类定义如下:

 

java代码:
  1. package org.apache.catalina.mbeans;   
  2. import javax.management.MBeanException;   
  3. import javax.management.RuntimeOperationsException;   
  4. import org.apache.commons.modeler.BaseModelMBean;   
  5. public class ClassNameMBean extends BaseModelMBean {   
  6.    public ClassNameMBean() throws MBeanException, RuntimeOperationsException {   
  7.      super();   
  8.    }   
  9.    public String getClassName() {   
  10.      return (this.resource.getClass().getName());   
  11.    }   
  12. }  

         ClassNameMBean类是BaseModelMBean的子类,其只写属性className在托管资源中不可见。mbeans-descriptors.xml文件中的很多mbean元素使用该类作为其model MBean。

20.6.2  StandardServerMBean

         StandardServerMBean类继承自org.apache.commons.modeler.BaseModelMBean类,用于管理org.apache.catalina.core.StandardServer。StandardServerMBean类覆盖了托管资源的一些方法,例如store方法。当管理应用程序调用store方法时,实际上会执行StandardServerMBean的store方法,而不是StandardServer的store方法。

 

java代码:
  1. package org.apache.catalina.mbeans;   
  2. import javax.management.InstanceNotFoundException;   
  3. import javax.management.MBeanException;   
  4. import javax.management.MBeanServer;   
  5. import javax.management.RuntimeOperationsException;   
  6. import org.apache.catalina.Server;   
  7. import org.apache.catalina.ServerFactory;   
  8. import org.apache.catalina.core.StandardServer;   
  9. import org.apache.commons.modeler.BaseModelMBean;   
  10. public class StandardServerMBean extends BaseModelMBean {   
  11.    private static MBeanServer mserver = MBeanUtils.createServer();   
  12.    public StandardServerMBean() throws MBeanException, RuntimeOperationsException {   
  13.      super();   
  14.    }   
  15.    public synchronized void stored throws InstanceNotFoundException, MBeanException,  
  16. RuntimeOperationsException {   
  17.      Server server = ServerFactory.getServer();   
  18.      if (server instanceof StandardServer) {   
  19.        try {   
  20.          ((StandardServer) server).store();   
  21.        } catch (Exception e) {   
  22.          throw new MBeanException(e, "Error updating conf/server.xml");   
  23.        }   
  24.      }   
  25.    }   
  26. }  

20.6.3  MBeanFactory

         MBeanFactory类表示一个工程对象,用于创建管理tomcat资源的model Mbean。MBeanFactory类还提供了删除MBean的方法。createStandardContext方法用于创建托管资源StandardContext的model MBean:

 

java代码:
  1. public String createStandardContext(String parent, String path, String docBase) throws Exception {   
  2.    // Create a new StandardContext instance   
  3.    StandardContext context = new StandardContext();   
  4.    path = getPathStr(path);   
  5.    context.setPath(path);   
  6.    context.setDocBase(docBase);   
  7.    ContextConfig contextConfig = new ContextConfig();   
  8.    context.addLifecycleListener(contextConfig);   
  9.    // Add the new instance to its parent component   
  10.    ObjectName pname = new ObjectName(parent);   
  11.    Server server = ServerFactory.getServer();   
  12.    Service service = server.findService(pname.getKeyProperty("service"));   
  13.    Engine engine = (Engine) service.getContainer();   
  14.    Host host = (Host) engine.findChild(pname.getKeyProperty("host"));   
  15.    // Add context to the host   
  16.    host.addChild(context);   
  17.    // Return the corresponding MBean name   
  18.    ManagedBean managed = registry.findManagedBean("StandardContext");   
  19.    ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), context);   
  20.    return (oname.toString());   
  21. }  

20.6.4  MBeanUtil

         org.apache.catalina.mbeans.MBeanUtil类是一个工具类,提供了一些静态方法用于创建各种管理Cataliana对象的MBean,还有一些静态方法用于删除MBean,创建ObjectName等。例如,使用createMBean方法创建创建一个管理org.apache.catalina.Server的MBean。createMBean的实现方法如下:

 

java代码:
  1. public static ModelMBean createMBean(Server server) throws Exception {   
  2.    String mname = createManagedName(server);   
  3.    ManagedBean managed = registry.findManagedBean(mname);   
  4.    if (managed == null) {   
  5.      Exception e = new Exception( "ManagedBean is not found with "+mname);   
  6.      throw new MBeanException(e);   
  7.    }   
  8.    String domain = managed.getDomain();   
  9.    if (domain == null)   
  10.      domain = mserver.getDefaultDomain();   
  11. ModelMBean mbean = managed.createMBean(server);   
  12.    ObjectName oname = createObjectName(domain, server);   
  13.    mserver.registerMBean(mbean, oname);   
  14.    return (mbean);   
  15. }  

20.7  创建Catalian的MBean

前面的章节说明了catalina中的一些model MBean,现在来说明下这些mbean的创建。

         在server.xml中定义了如下的监听器:

 

java代码:
  1. <Server port="8005" shutdown="SHUTDOWN" debug="0">   
  2.    <Listener c1assName="org.apache.catalina.mbeans.ServerLifecycleListener" debug="0"/>   
  3. ...  

         这里为StandardServer添加了一个监听器,org.apache.catalina.mbeans.ServerLifecycleListener。当StandardServer启动时,会触发START_EVENT事件:

 

java代码:
  1. public void start() throws LifecycleException {   
  2.    ...   
  3.    lifecycle.fireLifecycleEvent(START_EVENT, null);   
  4.    ...   
  5. }  

而当StandardServer关闭时,会触发STOP_EVENT事件:

 

java代码:
  1. public void stop() throws LifecycleException {   
  2.    ...   
  3.    lifecycle.fireLifecycleEvent(STOP_EVENT, null);   
  4.    ...   
  5. }  

这些事件会执行ServerLifecycleListener的lifecycleEvent方法,下面是lifecycleEvent方法的实现:

 

java代码:
  1. public void lifecycleEvent(LifecycleEvent event) {   
  2.    Lifecycle lifecycle = event.getLifecycle();   
  3.    if (Lifecycle.START_EVENT.equals(event.getType())) {   
  4.      if (lifecycle instanceof Server) {   
  5.        // Loading additional MBean descriptors   
  6.        loadMBeanDescriptors();   
  7.        createMBeans();   
  8.      }   
  9.    } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {   
  10.      if (lifecycle instanceof Server) {   
  11.        destroyMBeans();   
  12.      }   
  13.    } else if (Context.RELOAD_EVENT.equals(event.getType())) {   
  14.      if (lifecycle instanceof StandardContext) {   
  15.        StandardContext context = (StandardContext)lifecycle;   
  16.        if (context.getPrivileged()) {            
  17. context.getServletContext().setAttribute (Globals.MBEAN_REGISTRY_ATTR,   
  18.        MBeanUtils.createRegistry());   
  19.          context.getServletContext().setAttribute (Globals.MBEAN_SERVER_ATTR,   
  20.         MBeanUtils.createServer());   
  21.        }   
  22.      }   
  23.    }   
  24. }  

         其中,createMBeans方法用于创建MBean,该方法会先创建MBeanFactory实例,然后在创建相应的MBean。ServerLifecycleListener类中的createMBeans方法实现如下:

 

java代码:
  1. protected void createMBeans() {   
  2.    try {   
  3.      MBeanFactory factory = new MBeanFactory();   
  4.      createMBeans(factory);   
  5.      createMBeans(serverFactory.getserver());   
  6.    } catch (MBeanException t) {   
  7.      Exception e = t.getTargetException();   
  8.      if (e == null)   
  9.        e = t;   
  10.      log("createMBeans: MBeanException", e);   
  11.    } catch (Throwable t) {   
  12.      log("createMBeans: Throwable", t);   
  13.    }   
  14. }  

         第一个createMBeans方法会使用MBeanUtil类为MBeanFactory创建一个ObejctName,然后将其注册到MBeanServer中。第二个createMBeans方法获取一个org.apache.catalina.Server对象,为其创建model MBean。下面的代码展示例如如何为Server对象创建一个MBean:

 

java代码:
  1. protected void createMBeans(Server server) throws Exception {   
  2.    // Create the MBean for the Server itself   
  3.    if (debug >= 2)   
  4.      log("Creating MBean for Server " + server);   
  5. MBeanUtils.createMBean(server);   
  6.    if (server instanceof StandardServer) {   
  7.      ((StandardServer) server).addPropertyChangeListener(this);   
  8.    }   
  9.    // Create the MBeans for the global NamingResources (if any)   
  10.    NamingResources resources = server.getGlobalNamingResources();   
  11.    if (resources != null) {   
  12.      createMBeans(resources);   
  13.    }   
  14.    // Create the MBeans for each child Service   
  15.    Service services[] = server.findServices();   
  16.    for (int i = 0; i < services.length; i++) {   
  17.      // FIXME - Warp object hierarchy not currently supported   
  18.      if (services[i].getContainer().getClass().getName().equals   
  19.        ("org.apache.catalina.connector.warp.WarpEngine")) {   
  20.        if (debug >= 1) {   
  21.           log("Skipping MBean for Service " + services[i]);   
  22.        }   
  23.        continue;   
  24.      }   
  25.      createMBeans(services[i]);   
  26.    }   
  27. }  

注意,createMBeans方法调用下面的语句

 

java代码:
  1. createMBeans(services[i]);  

遍历所有的StandardServer对象中所有的Service。该方法为每个service对象创建MBean,然后,为每个service对象中所有的connector和engine对象调用createMBeans方法。

         创建service mbean的createMBeans方法实现如下:

 

java代码:
  1. protected void createMBeans(Service service) throws Exception {   
  2.    // Create the MBean for the Service itself   
  3.    if (debug >= 2)   
  4.      log("Creating MBean for Service " + service);   
  5.    MBeanUtils.createMBean(service);   
  6.    if (service instanceof StandardService) {   
  7.      ((StandardService) service).addPropertyChangeListener(this);   
  8.    }   
  9.    // Create the MBeans for the corresponding Connectors   
  10.    Connector connectors[] = service.findConnectors();   
  11.    for (int j = 0; j < connectors.length; j++) {   
  12.      createMBeans(connectors[j]);   
  13.    }   
  14.    // Create the MBean for the associated Engine and friends   
  15.    Engine engine = (Engine) service.getContainer();   
  16.    if (engine != null) {   
  17.      createMBeans(engine);   
  18.    }   
  19. }  

同样的,对每个engine对象,使用createMBeans方法为每个host创建mbean:

 

java代码:
  1. protected void createMBeans(Engine engine) throws Exception {   
  2.    // Create the MBean for the Engine itself   
  3.    if (debug >= 2) {   
  4.      log("Creating MBean for Engine " + engine);   
  5.    }   
  6.   MBeanUtils.createMBean(engine);   
  7.    ...   
  8.    Container hosts[] = engine.findChildren();   
  9.    for (int j = 0; j < hosts.length; j++) {   
  10.      createMBeans((Host) hosts[j]);   
  11.    }   
  12.    ...   
  13. }  

接着为每个host,使用createMBeans方法,为每个context创建mbean:

 

java代码:
  1. protected void createMBeans(Host host) throws Exception {   
  2.    ...   
  3.    MBeanUtils.createMBean(host);   
  4.    ...   
  5.    Container contexts[] = host.findChildren();   
  6.    for (int k = 0; k < contexts.length; k++) {   
  7.      createMBeans((Context) contexts[k]);   
  8.    }   
  9.    ...   
  10. }  

以此类推,createMBeans (context)方法实现如下:

 

java代码:
  1. protected void createMBeans(Context context) throws Exception {   
  2.    ...   
  3.    MBeanUtils.createMBean(context);   
  4.    ...   
  5.    context.addContainerListener(this);   
  6.    if (context instanceof StandardContext) {   
  7.      ((StandardContext) context).addPropertyChangeListener(this);   
  8.      ((StandardContext) context).addLifecycleListener(this);   
  9.    }   
  10.    // If the context is privileged, give a reference to it   
  11.    // in a servlet context attribute   
  12.    if (context.getPrivileged()) {   
  13.      context.getServletContext().setAttribute   
  14.        (Globals.MBEAN_REGISTRY_ATTR, MBeanUtils.createRegistry());   
  15.      context.getServletContext().setAttribute   
  16.        (Globals.MBEAN_SERVER_ATTR, MBeanUtils.createServer());   
  17.    }   
  18.    ...   
  19. }  

         如果context的privileged属性为true,则会为context添加两个属性,两个属性的key分别是Globals.MBEAN_REGISTRY_ATTR和Globals.MBEAN_SERVER_ATTR。下面是org.apache.catalina.Globals类的实现片段:

 

java代码:
  1. /**  
  2.   * The servlet context attribute under which the managed bean Registry  
  3.   * will be stored for privileged contexts (if enabled).  
  4.   */   
  5. public static final String MBEAN_REGISTRY_ATTR = "org.apache.catalina.Registry";   
  6. /**  
  7.   * The servlet context attribute under which the MBeanServer will be  
  8.   * stored for privileged contexts (if enabled).  
  9.   */   
  10. public static final String MBEAN_SERVER_ATTR = "org.apache.catalina.MBeanServer";  

         MBeanUtils.createRegistry方法返回一个Registry实例,MBeanUtils.createServer方法返回一个javax.management.MBeanServer实例,catalina的mbean就注册于此。换句话说,当privileged属性为true时,你就可以从一个web应用中获取Registry和MBeanServer对象。

20.8  应用程序

         该应用程序用来管理tomcat,虽然简单,但说明了如何在tomcat中使用mbean。你可以列出catalina中所有的ObjectName对象,以及当前正在运行的context,并删除其中的任意一个。

         首先要为web应用创建描述符,该描述文件需要放到%CATALINA_HOME%/webapps目录下:

 

java代码:
  1. <Context path="/myadmin" docBase="../server/webapps/myadmin" debug="8"   
  2. privileged="true" reloadable="true">   
  3. </Context>  

注意,这里privileged属性的值必须为true,docBase指定了web应用的具体路径。该web应用中包含了一个servlet,实现代码如下:

下面编写一个web.xml文件:

 

java代码:
  1. <?xml version="1.0" encoding="ISO-8859-1"?>   
  2. <!DOCTYPE web-app   
  3.      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   
  4.       "http://java.sun.com/dtd/web-app_2_3.dtd">   
  5. <web-app>   
  6.    <servlet>        
  7. <servlet-name>myAdmin</servlet-name>   
  8.      <servlet-class>myadmin.MyAdminServlet</servlet-class>   
  9.    </servlet>   
  10.    <servlet-mapping>   
  11.      <servlet-name>myAdmin</servlet-name>   
  12.      <url-pattern>/myAdmin</url-pattern>   
  13.    </servlet-mapping>   
  14. </web-app>  

执行后,要想列出所有的ObjectName对象,可以使用如下的url:

http://localhost:8080/myadmin/myAdmin?action=listAllMBeans

列出所有的web应用可以使用如下的url:

http://localhost:8080/myadmin/myAdmin?action=listAllContexts

 

转载请注明出处【http://sishuok.com/forum/blogPost/list/4202.html

 

 

源码下载地址:【http://sishuok.com/forum/blogPost/list/0/4061.html

pdf下载地址:【http://sishuok.com/forum/blogPost/list/0/4061.html

 

译者博客:曹旭东

 

图书购买地址:http://product.china-pub.com/194735

阅读更多

没有更多推荐了,返回首页