标签:
因为JMX 提供了比 ContainerServlet接口更灵活的方法来管理tomcat。许多基于服务器的应用程序(如tomcat, JBoss,JONAS,Geronimo等),都使用了JMX 技术来管理各自的资源;
实际上,一个可由JMX 管理的资源可以是一个应用程序,一种实现,一个服务,一个设备,一个用户等。一个可由JMX管理的资源也可以由 java 编写,并提供一个相应的java包装;
4.1)若要使一个java对象成为一个可由JMX 管理的资源,则必须创建Managed Bean 或 MBean对象;(干货——引入了MBean)4.2)MBean会提供它所管理的一些java对象的属性和方法供管理应用程序使用;管理应用程序本身并不能直接访问托管的java对象,因此,可以选择java对象 的哪些属性和和方法可以由管理应用程序使用;4.3)当拥有了一个MBean类后,需要将其实例化,并将其注册到另一个作为 MBean服务器的java对象中;MBean 服务器中保存了应用程序中注册的所有MBean。管理应用程序通过MBean服务器来访问 MBean实例;(干货——MBean 服务器中保存了应用程序中注册的所有MBean。管理应用程序通过MBean服务器来访问 MBean实例)4.4)管理应用程序好比web 浏览器; 而MBean 服务器好比 servlet容器;
6.1)MBean服务器位于代理层:MBean 位于设备层,分布式服务层会在 JMX 规范将来的版本中涉及;6.2)设备层规范:定义了编写可由JMX 管理的资源的标准,即如何编写MBean;6.3)代理层定义了:创建代理的规范;代理封装了 MBean服务器,提供了处理MBean的服务;代理和它所管理的MBean 通常都位于同一个java 虚拟机中。由于JMX 规范附带了一个参考实现,所以并不需要自己编写MBean 服务器;
public interface MBeanServer extends MBeanServerConnection { //javax.management.loading.ClassLoaderRepository.MBeanServer public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException; }
A1)要调用registerMBean方法,需要传入一个待注册的MBean实例和一个 ObjectName 实例;A2)ObjectName实例与 HashMap中的键类似,它可以唯一标识一个 MBean实例;A3)registerMBean方法返回一个ObjectInstance 实例。java.management.ObjectInstance 类封装了一个 MBean实例的对象名称和它的类名;public class ObjectInstance implements Serializable { private static final long serialVersionUID = -4099952623687795850L; private ObjectName name; private String className; public ObjectInstance(String objectName, String className) throws MalformedObjectNameException { this(new ObjectName(objectName), className); } public ObjectInstance(ObjectName objectName, String className) { if (objectName.isPattern()) { final IllegalArgumentException iae = new IllegalArgumentException("Invalid name->"+ objectName.toString()); throw new RuntimeOperationsException(iae); } this.name= objectName; this.className= className; } public boolean equals(Object object) { if (!(object instanceof ObjectInstance)) { return false; } ObjectInstance val = (ObjectInstance) object; if (! name.equals(val.getObjectName())) return false; if (className == null) return (val.getClassName() == null); return className.equals(val.getClassName()); } public int hashCode() { final int classHash = ((className==null)?0:className.hashCode()); return name.hashCode() ^ classHash; } public ObjectName getObjectName() { return name; } public String getClassName() { return className; } public String toString() { return getClassName() + "[" + getObjectName() + "]"; } }
3.1)queryNames()方法: 返回一个java.util.Set 实例,其中包含了匹配某个指定模式对象名称的一组MBean 实例的对象名称;其方法签名为:public Set<ObjectName> queryNames(ObjectName name, QueryExp query);
A1)参数query 指定了过滤条件;A2)若参数name为null 或者没有域,而且指定了key 属性,那么会返回已经注册的MBean实例的所有 ObjectName实例。如果参数 queyr为null,则不会对查找对象进行过滤;
3.2)queryMBeans()方法:其方法签名如下:public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query);对以上代码的分析(Analysis):一旦获得了所需要 的MBean实例的对象名称,就可以操作托管资源在 MBean 实例中提供的属性或调用其方法;
4.1)MBeanServer.getAttribute()方法 和 setAttribute()方法:用于获取或设置已经注册的 MBean实例的属性;
public class ObjectName implements Comparable<ObjectName>, QueryExp { //javax.management.ObjectName
myDomain:type=Car,color=blue;
4.1)ObjectName实例可以在域部分或键值对部分使用通配符来表示模式,作为模式的 ObjectName实例可以有0个或多个键;
step1)创建一个接口,该接口的命名规范为: java类名+MBean后缀;如想要管理的java类名为Car,则需要创建命名为 CarMBean的接口;step2)修改java类,让其实现刚刚创建的 CarMBean接口;step3)创建一个代理,该代理类必须包含一个 MBeanServer实例;step4)为MBean创建 ObjectName 实例;step5)实例化 MBeanServer类;step6)将 MBean注册到 MBeanServer 中;
public class Car { private String color = "red"; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("Baby you can drive my car."); } }
2.1)修改Car类,使其实现CarMBean接口;public interface CarMBean { public String getColor(); public void setColor(String color); public void drive(); }public class Car implements CarMBean { private String color = "red"; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("Baby you can drive my car."); } }对以上代码的分析(Analysis):要在接口中声明Car 类中所要提供的所有方法;在CarMBean 接口中声明了 Car类的所有方法;2.2)给出用来创建标准MBean实例和管理Car 对象的代理类 StandardAgent的定义;public class StandardAgent { private MBeanServer mBeanServer = null; public StandardAgent() { mBeanServer = MBeanServerFactory.createMBeanServer(); } public MBeanServer getMBeanServer() { return mBeanServer; } public ObjectName createObjectName(String name) { ObjectName objectName = null; try { objectName = new ObjectName(name); } catch (Exception e) { } return objectName; } private void createStandardBean(ObjectName objectName, String managedResourceClassName) { try { mBeanServer.createMBean(managedResourceClassName, objectName); } catch (Exception e) { } } public static void main(String[] args) { StandardAgent agent = new StandardAgent(); // 创建标准类型MBean的代理. MBeanServer mBeanServer = agent.getMBeanServer(); // 创建MBean服务器 String domain = mBeanServer.getDefaultDomain(); // 设置域 String managedResourceClassName = "com.tomcat.chapter20.standardmbeantest.Car"; // 设置要管理的类的全限定名. ObjectName objectName = agent.createObjectName(domain + ":type=" + managedResourceClassName); // 创建 ObjectName 对象.(用于标识MBean) agent.createStandardBean(objectName, managedResourceClassName); //创建标准类型的MBean. // manage MBean try { Attribute colorAttribute = new Attribute("Color", "blue"); mBeanServer.setAttribute(objectName, colorAttribute); // 为该MBean设置属性. System.out.println(mBeanServer.getAttribute(objectName, "Color")); // 获取该MBean的属性. mBeanServer.invoke(objectName, "drive", null, null); // 调用该MBean的drive方法. } catch (Exception e) { e.printStackTrace(); } } }对以上代码的分析(Analysis):
A1)StandardAgent类是一个代理类:用来实例化 MBean服务器,并使用MBean服务器注册CarMBean实例;A2)首先要注意的是变量mBeanServer,StandardAgent类的构造函数会将一个 MBeanServer实例赋值给变量 MBeanServer。构造函数会调用MBeanServerFactory.createMBeanServer()方法创建一个MBean服务器实例;
A3)StandardAgent.createObjectName()会根据传入的字符串参数返回一个 ObjectName实例;public ObjectName createObjectName(String name) { ObjectName objectName = null; try { objectName = new ObjectName(name); } catch (Exception e) { } return objectName; }A4)StandardAgent.createStandardMBean()方法会调用 MBeanServer.createMBean()方法;createMBean()方法接收托管资源的类名和一个 ObjectName实例,该 ObjectName实例唯一地标识了为托管资源创建的MBean实例。createMBean()方法也会将创建的 MBean实例注册到 MBeanServer中;由于标准MBean 实例遵循了特定的命名规则,因此不需要为 createMBean()方法提供MBean的类名。如果托管资源的 类名是 Car,则创建的 MBean 的类名是 CarMBean;private void createStandardBean(ObjectName objectName, String managedResourceClassName) { try { mBeanServer.createMBean(managedResourceClassName, objectName); } catch (Exception e) { } }
StandardAgent agent = new StandardAgent(); MBeanServer mBeanServer = agent.getMBeanServer();
String domain = mBeanServer.getDefaultDomain(); String managedResourceClassName = "com.tomcat.chapter20.standardmbeantest.Car"; ObjectName objectName = agent.createObjectName(domain + ":type=" + managedResourceClassName);5)然后,main()方法会调用 createStandardBean()方法,并传入对象名称和托管资源的类名;
agent.createStandardBean(objectName, managedResourceClassName);
// manage MBean try { Attribute colorAttribute = new Attribute("Color", "blue"); mBeanServer.setAttribute(objectName, colorAttribute); System.out.println(mBeanServer.getAttribute(objectName, "Color")); mBeanServer.invoke(objectName, "drive", null, null); }
blue Baby you can drive my car.
A1)我们很想知道,到底为什么需要使用 JMX 来管理 java对象呢?A2)上面的荔枝中,我们可以通过 StandardAgent 类来直接访问Car对象了;这里的关键问题是可以选择哪些功能需要暴露出来,哪些方法需要对外隐藏;(干货——这里的关键问题是可以选择哪些功能需要暴露出来,哪些方法需要对外隐藏)
2.1)在使用标准MBean管理资源时,需要定义一个接口;然后让托管资源实现该接口;而使用模型MBean时,不需要定义接口;相反,可以使用 javax.management.modelmbean.ModelMBean 接口来表示模型MBean,只需要实现该接口;2.2)在JMX 的参考实现中有一个 javax.management.modelmbean.RequiredModelMBean类,是ModelMBean接口的默认实现, 可以实例化 RequiredModelMBean 类或其子类;
4.1)ModelMBeanInfo对象描述了将会暴露给代理的构造函数,属性,操作甚至是监听器;
method1)传入一个 ModelMBeanInfo 对象到 RequiredModelBean 对象的构造函数中 ;method2)调用 RequiredModelMBean 对象的 setModelMBeanInfo()方法,并传入一个 ModelMBeanInfo对象;
public void setManagedResource(Object mr, String mr_type) throws MBeanException, RuntimeOperationsException, InstanceNotFoundException, InvalidTargetObjectTypeException ;
public interface ModelMBeanInfo{ public Descriptor[] getDescriptors(String inDescriptorType) throws MBeanException, RuntimeOperationsException; public void setDescriptors(Descriptor[] inDescriptors) throws MBeanException, RuntimeOperationsException; public Descriptor getDescriptor(String inDescriptorName, String inDescriptorType) throws MBeanException, RuntimeOperationsException; public Descriptor getMBeanDescriptor() throws MBeanException, RuntimeOperationsException; public void setMBeanDescriptor(Descriptor inDescriptor) throws MBeanException, RuntimeOperationsException; public ModelMBeanAttributeInfo getAttribute(String inName) throws MBeanException, RuntimeOperationsException; public ModelMBeanOperationInfo getOperation(String inName) throws MBeanException, RuntimeOperationsException; public ModelMBeanNotificationInfo getNotification(String inName) throws MBeanException, RuntimeOperationsException; public java.lang.Object clone(); public MBeanAttributeInfo[] getAttributes(); public java.lang.String getClassName(); public MBeanConstructorInfo[] getConstructors(); public java.lang.String getDescription(); public MBeanNotificationInfo[] getNotifications(); public MBeanOperationInfo[] getOperations(); }
2.1)构造函数是 javax.management.modelmbean.ModelMBeanConstructorInfo 类的实例,属性是 javax.management.modelmbean.MOdelMBeanAttributeInfo 类的实例,方法是 javax.management.modelmbean.ModelMBeanOperationInfo 类的实例,监听器是javax.management.modelmbean.ModelMBeanNotificationInfo 类的实例;2.2)JMX 提供了ModelMBeanInfo接口的默认实现,即 javax.management.modelmbean.ModelMBeanInfoSupport类;public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { // javax.management.modelmbean.ModelMBeanInfoSupport public ModelMBeanInfoSupport(String className, String description, ModelMBeanAttributeInfo[] attributes, ModelMBeanConstructorInfo[] constructors, ModelMBeanOperationInfo[] operations, ModelMBeanNotificationInfo[] notifications) { this(className, description, attributes, constructors, operations, notifications, null); } }
1.1)Car 类的源码定义public class Car { private String color = "red"; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("Baby you can drive my car."); } }1.2)对于模型MBean,不需要像使用标准MBean那样,编写一个接口。只需要实例化RequiredMBean类;public class ModelAgent { private String MANAGED_CLASS_NAME = "com.tomcat.chapter20.modelmbeantest1.Car"; private MBeanServer mBeanServer = null; public ModelAgent() { mBeanServer = MBeanServerFactory.createMBeanServer(); } public MBeanServer getMBeanServer() { return mBeanServer; } private ObjectName createObjectName(String name) { ObjectName objectName = null; try { objectName = new ObjectName(name); } catch (MalformedObjectNameException e) { e.printStackTrace(); } return objectName; } private ModelMBean createMBean(ObjectName objectName, String mbeanName) { ModelMBeanInfo mBeanInfo = createModelMBeanInfo(objectName, mbeanName); RequiredModelMBean modelMBean = null; try { modelMBean = new RequiredModelMBean(mBeanInfo); } catch (Exception e) { e.printStackTrace(); } return modelMBean; } private ModelMBeanInfo createModelMBeanInfo(ObjectName inMbeanObjectName, String inMbeanName) { ModelMBeanInfo mBeanInfo = null; ModelMBeanAttributeInfo[] attributes = new ModelMBeanAttributeInfo[1]; ModelMBeanOperationInfo[] operations = new ModelMBeanOperationInfo[3]; try { attributes[0] = new ModelMBeanAttributeInfo("Color", "java.lang.String", "the color.", true, true, false, null); operations[0] = new ModelMBeanOperationInfo("drive", "the drive method", null, "void", MBeanOperationInfo.ACTION, null); operations[1] = new ModelMBeanOperationInfo("getColor", "get color attribute", null, "java.lang.String", MBeanOperationInfo.ACTION, null); Descriptor setColorDesc = new DescriptorSupport(new String[] { "name=setColor", "descriptorType=operation", "class=" + MANAGED_CLASS_NAME, "role=operation" }); MBeanParameterInfo[] setColorParams = new MBeanParameterInfo[] { (new MBeanParameterInfo( "new color", "java.lang.String", "new Color value")) }; operations[2] = new ModelMBeanOperationInfo("setColor", "set Color attribute", setColorParams, "void", MBeanOperationInfo.ACTION, setColorDesc); mBeanInfo = new ModelMBeanInfoSupport(MANAGED_CLASS_NAME, null, attributes, null, operations, null); } catch (Exception e) { e.printStackTrace(); } return mBeanInfo; } public static void main(String[] args) { ModelAgent agent = new ModelAgent(); // 创建模型MBean代理. MBeanServer mBeanServer = agent.getMBeanServer(); // 创建MBean 服务器. Car car = new Car(); String domain = mBeanServer.getDefaultDomain(); // 创建 域 String managedResourceClassName = "com.tomcat.chapter20.modelmbeantest1.Car"; // 设置要管理的类的全限定名. ObjectName objectName = agent.createObjectName(domain + ":type=" + managedResourceClassName); // 创建 ObjectName 对象.(用于标识MBean) String mBeanName = "myMBean"; ModelMBean modelMBean = agent.createMBean(objectName, mBeanName); //创建模型类型的MBean. try { modelMBean.setManagedResource(car, "ObjectReference"); // 为该模型MBean 设置资源类型 mBeanServer.registerMBean(modelMBean, objectName); // 将该模型MBean 注册到 MBean 服务器. } catch (Exception e) { } // manage the bean try { Attribute attribute = new Attribute("Color", "green"); mBeanServer.setAttribute(objectName, attribute); String color = (String) mBeanServer.getAttribute(objectName, "Color"); System.out.println("Color:" + color); // 设置属性->获取属性->打印属性 attribute = new Attribute("Color", "blue"); mBeanServer.setAttribute(objectName, attribute); color = (String) mBeanServer.getAttribute(objectName, "Color"); System.out.println("Color:" + color); // 设置属性->获取属性->打印属性 mBeanServer.invoke(objectName, "drive", null, null); // 调用MBean 服务器中表示为 objectName的MBean对象的drive方法 } catch (Exception e) { e.printStackTrace(); } } }public class Car { public Car() { System.out.println("Car constructor"); } private String color = "red"; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("Baby you can drive my car."); } }1.3)Console info :Color:green Color:blue Baby you can drive my car.
2.1)problem:在前面的荔枝中,创建RequiredModelMBean 对象 ,需要创建一个对象ModelMBeanInfo 对象,并将其传递给 RequiredModelMBean 的构造函数 ,(ModelMBeanInfo 对象:描述了将要由 MBean实例暴露出的属性和方法;)private ModelMBean createMBean(ObjectName objectName, String mbeanName) { ModelMBeanInfo mBeanInfo = createModelMBeanInfo(objectName, mbeanName); RequiredModelMBean modelMBean = null; try { modelMBean = new RequiredModelMBean(mBeanInfo); } //.......2.2)solution: 使用Commons Modeler 库,就不再需要创建 ModelMBeanInfo对象了;相反,对模型MBean的描述被封装在一个 org.apache.catalina.modeler.ManagedBean对象中。不需要编写代码在MBean中暴露属性和方法。只需要编写一个mbean的描述符文件(一个XML文档),列出想要创建的 MBean。
3.1)然后,调用MAnagedBean.createMBean()方法创建模型MBean。这之后就是普通的流程了。3.2)下面介绍mbean描述符文件的格式, 然后讨论Modeler库中的3个重要的类,分别是 Registry类,ManagedBean类 和 BaseModelMBean类;
1.1)<mbeans-descriptors>根元素: 在<mbeans-descriptors>标签内部是 mbean元素,每个mbean标签表示一个模型MBean。mbean元素包含了分别用来表示属性,方法,构造函数和通知的元素;看个荔枝)car-mbean-descriptor.xml 代码定义如下:<?xml version="1.0"?> <!DOCTYPE mbeans-descriptors PUBLIC "-//Apache Software Foundation//DTD Model MBeans Configuration File" "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd"> <mbeans-descriptors> <mbean name="myMBean" className="javax.management.modelmbean.RequiredModelMBean" description="The ModelMBean that manages our Car object" type="com.tomcat.chapter20.modelmbeantest2.Car"> <attribute name="Color" description="The car color" type="java.lang.String"/> <operation name="drive" description="drive method" impact="ACTION" returnType="void"> <parameter name="driver" description="the driver parameter" type="java.lang.String"/> </operation> </mbean> </mbeans-descriptors>
A1)mbean元素:该元素描述一个模型 MBean,包含创建对应 ModelMBeanInfo 对象 的信息。mbean元素的定义如下所示:
<!Element mmean (descriptor?, attribute*, constructor*, notification*, operation*)>
A1.1)mbean元素可以有如下属性(property):
property1)name:唯一标识模型MBean的名称;一般case下,会使用相关服务器组件的基类名;property2)domain:在创建ModelMBean的ObjectName时,托管的 bean 创建的 ModelMBean 实例被注册到的 MBean服务器的域名;property3)description:对该 mbean的 简单描述;property4)group;组分类的可选名,用来选择具有相似MBean 实现类的组;property5)type:托管资源实现类的完全限定的java类名;property6)className:实现ModelMBean接口的 java类的完全限定名,若该属性未赋值,则默认使用 org.apache.commons.modeler.BaseModelMBean类;
A2)attribute元素:使用attribute元素 描述 MBean的 JavaBean属性。有如下属性:
property1)description:该属性的简单描述;property2)displayName:该属性的显示名称;property3)getMethod:由 attribute元素表示的属性的 getter()方法;property4)is:一个布尔值,指明该属性是否是一个布尔值,是否有 getter()方法,默认case下,该属性值为false;property5)name:该java bean属性的名称;property6)readable:一个布尔值,指定该属性对管理应用程序来说是否可读,该属性值默认为true;property7)setMethod:由 attribute 元素表示的属性的 setter()方法;property8)type:该属性的完全限定的java类名;property9)writeable:一个布尔值,表明该属性对管理应用程序来说是否可写,该属性默认为 true;
A3)operation元素:该元素描述了模型 MBean中要暴露给管理应用程序的公共方法,它可以有0个或多个 parameter 子元素和如下 的属性:
property1)description:方法的简单描述;property2)impact:指明方法的影响,可选值为,ACTION, ACTION-INFO, INFO 或 UNKNOWN;property3)name:公共方法名称;property4)returnType:方法返回值的完全限定的 java类名;
A4)parameter元素:该元素描述了将要传递给 构造函数或方法的参数,有如下属性;
property1)description:该参数的简单描述;property2)name:参数名;property3)type:参数的完全限定名的java类名;
<mbean name="MBeanFactory" type="org.apache.catalina.mbeans.MBeanFactory" description="Factory for MBeans and corresponding components" domain="Catalina"> <!-- IMPLEMENTATION NOTE - all of the createXxxxx methods create a new --> <!-- component and attach it to Catalina's component tree. The return --> <!-- value is the object name of the corresponding MBean for the new --> <!-- component. --> <operation name="createAccessLoggerValve" description="Create a new AccessLoggerValve" impact="ACTION" returnType="java.lang.String"> <parameter name="parent" description="MBean Name of the associated parent component" type="java.lang.String"/> </operation> //...... </mbean>
case1)需要覆盖托管资源的属性或方法;case2)需要添加在托管资源中没有定义的属性或方法;
method1)获取javax.management.MBeanServer 类的一个实例,所以不再需要调用 javax.management.MBeanServerFactory.createMBeanServer()方法了;method2)使用 loadRegistry() 方法读取 MBean 的描述符文件;method3)创建一个 ManagedBean 对象,用于创建模型 MBean的实例;
public class BaseModelMBean implements ModelMBean, MBeanRegistration { // org.apache.commons.modeler.BaseModelMBean protected Object resource = null; }
package com.tomcat.chapter20.modelmbeantest2; public class Car { public Car() { System.out.println("Car constructor"); } private String color = "red"; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("Baby you can drive my car."); } }
2.1)MBean的描述符文件为 car-mbean-descriptor.xml 文件,其代码定义如下:<?xml version="1.0"?> <!DOCTYPE mbeans-descriptors PUBLIC "-//Apache Software Foundation//DTD Model MBeans Configuration File" "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd"> <mbeans-descriptors> <mbean name="myMBean" className="javax.management.modelmbean.RequiredModelMBean" description="The ModelMBean that manages our Car object" type="com.tomcat.chapter20.modelmbeantest2.Car"> <attribute name="Color" description="The car color" type="java.lang.String"/> <operation name="drive" description="drive method" impact="ACTION" returnType="void"> <parameter name="driver" description="the driver parameter" type="java.lang.String"/> </operation> </mbean> </mbeans-descriptors>2.2)需要一个代理类 ModelAgent.java,具体定义如下:(干货——这里不需要创建ModelMBeanInfo 对象)public class ModelAgent { private Registry registry; private MBeanServer mBeanServer; public ModelAgent() { registry = createRegistry(); try { mBeanServer = Registry.getServer(); } catch (Throwable t) { t.printStackTrace(System.out); System.exit(1); } } public MBeanServer getMBeanServer() { return mBeanServer; } public Registry createRegistry() { Registry registry = null; try { URL url = ModelAgent.class .getResource("/com/tomcat/chapter20/modelmbeantest2/car-mbean-descriptor.xml"); InputStream stream = url.openStream(); Registry.loadRegistry(stream); stream.close(); registry = Registry.getRegistry(); } catch (Throwable t) { System.out.println(t.toString()); } return (registry); } public ModelMBean createModelMBean(String mBeanName) throws Exception { ManagedBean managed = registry.findManagedBean(mBeanName); if (managed == null) { System.out.println("ManagedBean null"); return null; } ModelMBean mbean = managed.createMBean(); ObjectName objectName = createObjectName(); return mbean; } private ObjectName createObjectName() { ObjectName objectName = null; String domain = mBeanServer.getDefaultDomain(); try { objectName = new ObjectName(domain + ":type=MyCar"); } catch (MalformedObjectNameException e) { e.printStackTrace(); } return objectName; } public static void main(String[] args) { ModelAgent agent = new ModelAgent(); // 创建模型MBean代理. MBeanServer mBeanServer = agent.getMBeanServer(); // 创建MBean 服务器. Car car = new Car(); System.out.println("Creating ObjectName"); ObjectName objectName = agent.createObjectName(); // 创建 ObjectName,作为MBean的标识对象. try { ModelMBean modelMBean = agent.createModelMBean("myMBean"); // 创建模型MBean. modelMBean.setManagedResource(car, "ObjectReference"); // 对象引用资源. mBeanServer.registerMBean(modelMBean, objectName); // 注册模型MBean 到 MBean 服务器.(objectName 是标识符) } catch (Exception e) { System.out.println(e.toString()); } // manage the bean try { Attribute attribute = new Attribute("Color", "green"); mBeanServer.setAttribute(objectName, attribute); // 创建属性并设置到 MBean服务器中标识为objectName的MBean. String color = (String) mBeanServer.getAttribute(objectName, "Color"); System.out.println("Color:" + color); // 获取属性并打印. attribute = new Attribute("Color", "blue"); mBeanServer.setAttribute(objectName, attribute); color = (String) mBeanServer.getAttribute(objectName, "Color"); System.out.println("Color:" + color); // 设置属性->获取属性->打印属性 mBeanServer.invoke(objectName, "drive", null, null); // 调用MBean 服务器中表示为 objectName的MBean对象的drive方法 } catch (Exception e) { e.printStackTrace(); } } }// 打印结果. Car constructor Creating ObjectName Color:green Color:blue Baby you can drive my car.<span style="font-family: SimSun; background-color: rgb(255, 255, 255);"> </span>
public class ClassNameMBean extends BaseModelMBean { // org.apache.catalina.mbeans.ClassNameMBean public ClassNameMBean() throws MBeanException, RuntimeOperationsException { super(); } public String getClassName() { return (this.resource.getClass().getName()); } }
public class StandardServerMBean extends BaseModelMBean { private static MBeanServer mserver = MBeanUtils.createServer(); public StandardServerMBean() throws MBeanException, RuntimeOperationsException { super(); } public synchronized void store() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { Server server = ServerFactory.getServer(); if (server instanceof StandardServer) { try { ((StandardServer) server).store(); } catch (Exception e) { throw new MBeanException(e, "Error updating conf/server.xml"); } } } }
public class MBeanFactory extends BaseModelMBean { //org.apache.catalina.mbeans.MBeanFactory.
public static ModelMBean createMBean(Connector connector) //org.apache.ccatlaina.mbeans.MBeanUtil.createMBean(). throws Exception { String mname = createManagedName(connector); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ModelMBean mbean = managed.createMBean(connector); ObjectName oname = createObjectName(domain, connector); mserver.registerMBean(mbean, oname); return (mbean); }
<Server port="8005" shutdown="SHUTDOWN"> <!-- Security listener. Documentation at /docs/config/listeners.html <Listener className="org.apache.catalina.security.SecurityListener" /> --> <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html --> <Listener className="org.apache.catalina.core.JasperListener" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> //......
A1)这里为服务器组件 org.apache.catalina.core.StandardServer 类的实例添加了一个 org.apache.catalina.mbeans.ServerLifecycleListener 类型的监听器。当StandardServer实例启动时,它会触发START_EVENT 事件,如 StandardServer.start()方法如下所示:public void start() throws LifecycleException { // org.apache.catalina.core.StandardServer.start(). // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("standardServer.start.started")); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Start our defined Services synchronized (services) { for (int i = 0; i < services.length; i++) { if (services[i] instanceof Lifecycle) ((Lifecycle) services[i]).start(); } } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }A2)而当 StandardServer对象关闭时,会触发 STOP_EVENT事件,如 StandardServer类定义的stop方法;A3)而这些时间会执行 ServerLifecycleListener.lifecycleEvnet()方法,其源代码定义如下:public void lifecycleEvent(LifecycleEvent event) { //org.apache.catalina.mbeans.ServerLifecycleListener.lifecycleEvent(). Lifecycle lifecycle = event.getLifecycle(); if (Lifecycle.START_EVENT.equals(event.getType())) { if (lifecycle instanceof Server) { // Loading additional MBean descriptors loadMBeanDescriptors(); createMBeans(); } // We are embedded. if( lifecycle instanceof Service ) { if( debug > 0 ) log( "Starting embeded" + lifecycle); try { MBeanFactory factory = new MBeanFactory(); createMBeans(factory); loadMBeanDescriptors(); createMBeans((Service)lifecycle); } catch( Exception ex ) { log("Error registering the service", ex); } } /* // Ignore events from StandardContext objects to avoid // reregistering the context if (lifecycle instanceof StandardContext) return; createMBeans(); */ } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { if (lifecycle instanceof Server) { destroyMBeans(); } } else if (Context.RELOAD_EVENT.equals(event.getType())) { // Give context a new handle to the MBean server if the // context has been reloaded since reloading causes the // context to lose its previous handle to the server if (lifecycle instanceof StandardContext) { // If the context is privileged, give a reference to it // in a servlet context attribute StandardContext context = (StandardContext)lifecycle; if (context.getPrivileged()) { context.getServletContext().setAttribute (Globals.MBEAN_REGISTRY_ATTR, MBeanUtils.createRegistry()); context.getServletContext().setAttribute (Globals.MBEAN_SERVER_ATTR, MBeanUtils.createServer()); } } } }
protected void createMBeans() { // org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(). try { MBeanFactory factory = new MBeanFactory(); createMBeans(factory); createMBeans(ServerFactory.getServer()); }//...... }
A1)第一个 createMBeans方法:会使用MBeanUtil类为 MBeanFactory实例创建一个 ObjectName,然后将其注册到 MBean服务器中;protected void createMBeans(MBeanFactory factory) throws Exception { // Create the MBean for the MBeanFactory if (debug >= 2) log("Creating MBean for MBeanFactory " + factory); MBeanUtils.createMBean(factory); }A2)第二个 createMBeans方法:该方法接收一个 org.apache.catalina.Server 对象,为其创建一个模型 MBean;protected void createMBeans(Server server) throws Exception { // Create the MBean for the Server itself if (debug >= 2) log("Creating MBean for Server " + server); MBeanUtils.createMBean(server); if (server instanceof StandardServer) { ((StandardServer) server).addPropertyChangeListener(this); } // Create the MBeans for the global NamingResources (if any) NamingResources resources = server.getGlobalNamingResources(); if (resources != null) { createMBeans(resources); } // Create the MBeans for each child Service Service services[] = server.findServices(); for (int i = 0; i < services.length; i++) { // FIXME - Warp object hierarchy not currently supported if (services[i].getContainer().getClass().getName().equals ("org.apache.catalina.connector.warp.WarpEngine")) { if (debug >= 1) { log("Skipping MBean for Service " + services[i]); } continue; } createMBeans(services[i]); } }
for (int i = 0; i < services.length; i++) { // FIXME - Warp object hierarchy not currently supported if (services[i].getContainer().getClass().getName().equals ("org.apache.catalina.connector.warp.WarpEngine")) { if (debug >= 1) { log("Skipping MBean for Service " + services[i]); } continue; } createMBeans(services[i]); //highlight line. }
A1)该方法为每个Service对象创建 MBean,然后,为每个Service对象中所有的连接器和Engine对象调用createMBean() 方法 创建 MBean实例;protected void createMBeans(Service service) throws Exception { // Create the MBean for the Service itself if (debug >= 2) log("Creating MBean for Service " + service); MBeanUtils.createMBean(service); if (service instanceof StandardService) { ((StandardService) service).addPropertyChangeListener(this); } // Create the MBeans for the corresponding Connectors Connector connectors[] = service.findConnectors(); for (int j = 0; j < connectors.length; j++) { createMBeans(connectors[j]); } // Create the MBean for the associated Engine and friends Engine engine = (Engine) service.getContainer(); if (engine != null) { createMBeans(engine); } }A2)createMBean(engine) 会调用 createMBean(Engine engine) 方法为每个Host实例创建MBean;protected void createMBeans(Engine engine) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(). // Create the MBean for the Engine itself if (debug >= 2) { log("Creating MBean for Engine " + engine); } MBeanUtils.createMBean(engine); engine.addContainerListener(this); if (engine instanceof StandardEngine) { ((StandardEngine) engine).addPropertyChangeListener(this); } //.......A3)createMBean(host) 会调用 createMBean(Host host) 方法为每个Context实例创建MBean;protected void createMBeans(Host host) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Host host). //...... MBeanUtils.createMBean(host); //...... Container contexts[] = host.findChildren(); for (int k = 0; k < contexts.length; k++) { createMBeans((Context) contexts[k]); } //...... }A4)createMBean(Context context) 方法的实现如下所示:protected void createMBeans(Context context) throws Exception { //org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans(Context context). //....... MBeanUtils.createMBean(context); context.addContainerListener(this); if (context instanceof StandardContext) { ((StandardContext) context).addPropertyChangeListener(this); ((StandardContext) context).addLifecycleListener(this); } if (context.getPrivileged()) { context.getServletContext().setAttribute (Globals.MBEAN_REGISTRY_ATTR, MBeanUtils.createRegistry()); context.getServletContext().setAttribute (Globals.MBEAN_SERVER_ATTR, MBeanUtils.createServer()); } //...... }
A1)如果Context实例的 privileged 属性为true,则会为 web 应用程序添加两个属性,并将其存储在 ServletContext对象中;两个属性的键名分别是 Globals.MBEAN_REGISTRY_ATTR 和 Globals.MBEAN_SERVER_ATTR, 定义如下:public static final String MBEAN_REGISTRY_ATTR = "org.apache.catalina.Registry"; public static final String MBEAN_SERVER_ATTR = "org.apache.catalina.MBeanServer";A2)MBeanUtils.createRegistry() 方法:返回一个 Registry实例,而createServer()方法返回一个 javax.management.MBeanServer 实例。Catalina中所有的MBean 都注册于 MBeanServer实例中;A3)换句话说:当privileged==true时,才可以从一个web 应用程序中获取 Registry 类 和 MBeanServer类的对象;
step1)为该web 应用程序创建描述符文件,如下所示:(该文件放到 %CATALINA_HOME%/webapps 目录下)<!-- myadmin.xml --> <?xml version="1.0" encoding="UTF-8"?> <Context path="/myadmin" docBase="./webapps/myadmin" debug="8" privileged="true" reloadable="true"> </Context>Attention)Context元素的privileged 必须为 true,docBase属性指定了web 应用程序的文件路径;step2)该web 应用程序包含一个servlet,代码如下:public class MyAdminServlet extends HttpServlet{ private Registry registry; private MBeanServer mBeanServer; @Override public void init() throws ServletException { registry = (Registry)getServletContext().getAttribute("org.apache.catalina.Registry"); if(registry == null) { System.out.println("registry not available"); return ; } mBeanServer = (MBeanServer)getServletContext().getAttribute("org.apache.catalina.MBeanServer"); if(mBeanServer == null) { System.out.println("mBeanServer not available"); return ; } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); if(registry == null) { System.out.println("registry not available"); return ; } out.println("<html><head></head><body>"); String action = request.getParameter("action"); if("listAllManagedBeans".equals(action)) { listAllManagedBeans(out); } else if("listAllContexts".equals(action)) { listAllContexts(out); }else if ("removeContext".equals(action)) { String contextObjectName = request.getParameter("contextObjectName"); removeContext(contextObjectName, out); } else { out.println("invalid commands."); } out.println("</body></html>"); } private void listAllManagedBeans(PrintWriter out) { String[] managedBeanNames = registry.findManagedBeans(); for (int i = 0; i < managedBeanNames.length; i++) { out.print(managedBeanNames[i] + "<br/>"); } } private void listAllContexts(PrintWriter out) { try { ObjectName objName = new ObjectName("Catalina:type=Context,*"); Set set = mBeanServer.queryNames(objName, null); Iterator it = set.iterator(); while(it.hasNext()) { ObjectName obj = (ObjectName)it.next(); out.print(obj + " <a href=?action=removeContext&contextObjectName=" + URLEncoder.encode(obj.toString(), "UTF-8") + ">remove</a><br/>"); } } catch (Exception e) { out.print(e.toString()); } } private void removeContext(String contextObjectName, PrintWriter out) { try { ObjectName mBeanFactoryOBjectName = new ObjectName("Catalina:type=MBeanFactory"); if(mBeanFactoryOBjectName != null) { String operation = "removeContext"; String[] params = new String[1]; params[0] = contextObjectName; String signature[] = {"java.lang.String"}; try { mBeanServer.invoke(mBeanFactoryOBjectName, operation, params, signature); out.print("context removed"); } catch (Exception e) { out.print(e.toString()); } } } catch (Exception e) { } } }step3)需要一个应用程序部署描述符文件。web.xml 代码如下:<?xml version="1.0" encoding="ISO-8859-1"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <servlet> <servlet-name>myAdmin</servlet-name> <servlet-class>myadmin.MyAdminServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myAdmin</servlet-name> <url-pattern>/myAdmin</url-pattern> </servlet-mapping> </web-app>
标签:
原文地址:http://blog.csdn.net/pacosonswjtu/article/details/51581048