您的位置:首页 > 运维架构 > Tomcat

tomcat(20)基于JMX的管理

2016-06-04 10:01 337 查看
【0】README

1)本文部分文字描述转自:“深入剖析tomcat”,旨在学习“tomcat(20)基于JMX的管理” 的相关知识;
2)晚辈我在tomcat上部署web 项目以测试JMX管理 tomcat 容器bean的效果,结果运行不成功,详情参见文末图片;

3)for complete source code, please visit  https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter20

【1】JMX 简介
1)intro:JMX == Java Management Extensions == JMX规范 == JMX管理扩展;
2)既然ContainerServlet接口已经有利用Manager应用程序访问Catalina的内部对象,那么为什么还要用 JMX呢?

因为JMX 提供了比 ContainerServlet接口更灵活的方法来管理tomcat。许多基于服务器的应用程序(如tomcat, JBoss,JONAS,Geronimo等),都使用了JMX 技术来管理各自的资源;

3)JMX规范定义了管理java 对象的的公开标准。如,tomcat 4  和 tomcat5 都使用JMX 来启用 servlet容器中的各种对象(如 Server对象, Host对象,Context对象,Valve对象等);
4)可由JMX 管理的资源:如果一个java对象可以由一个遵循JMX 规范的管理器应用程序管理,那么这个java对象称为一个可由JMX 管理的资源;(干货——可由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容器;

5)共有4种类型的MBean:标准类型,动态类型, 开放类型,模型类型:我们对模型类型尤其感兴趣,因为
Catalina中就使用了 模型类型的MBean;
6)从结构上讲,JMX 规范分为3层: 设备层,代理层 和 分布式服务层;

6.1)MBean服务器位于代理层:MBean 位于设备层,分布式服务层会在 JMX 规范将来的版本中涉及;
6.2)设备层规范:定义了编写可由JMX 管理的资源的标准,即如何编写MBean;
6.3)代理层定义了:创建代理的规范;代理封装了 MBean服务器,提供了处理MBean的服务;代理和它所管理的MBean 通常都位于同一个java 虚拟机中。由于JMX 规范附带了一个参考实现,所以并不需要自己编写MBean 服务器;

Attention)可以从下面的地址中下载JMX 规范和参考实现;http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html,
MX4J是一个开源版本的JMX,下载地址为:http://mx4j.sourceforge.net/

【2】JMX API
1)JMX的参考实现包含一个核心java库:这个库位于 javax.management 包 和 JMX 编程中具有特定功能的其他包下;

【2.1】 MBeanServer类(是 javax.management.MBeanServer 接口的实例)
1)要创建一个 MBeanServer的实例:只需要调用 javax.management.MBeanServerFactory 类的 createMBean()方法;
2)要将一个 MBean注册到 MBean服务器中,可以调用 MBeanServer.registerMBean()方法;下面是 registerMBean()方法的签名:
public interface MBeanServer extends MBeanServerConnection { //javax.management.loading.ClassLoaderRepository.MBeanServer
public ObjectInstance registerMBean(Object object, ObjectName name)
throws InstanceAlreadyExistsException, MBeanRegistrationException,
NotCompliantMBeanException;
}

对以上代码的分析(Analysis):

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)要想获取 MBean 实例或匹配某个模式的一组MBean实例,可以使用 MBeanServer接口提供的两个方法,分别是 queryNames()方法和 queryMBeans()方法;

3.1)queryNames()方法: 返回一个java.util.Set 实例,其中包含了匹配某个指定模式对象名称的一组MBean 实例的对象名称;其方法签名为:
public Set<ObjectName> queryNames(ObjectName name, QueryExp query);


对以上代码的分析(Analysis):

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)可以通过调用MBeanServer.invoke()方法 调用已经注册的 MBean实例的任何方法。

4.1)MBeanServer.getAttribute()方法 和 setAttribute()方法:用于获取或设置已经注册的 MBean实例的属性;

【2.2】ObjectName属性
1)intro:MBean实例注册于 MBean服务器中。MBean 服务器中的每个MBean实例都通过一个对象名称来唯一地标识,就好像是 HashMap 中都每个条目都通过一个键来表示一样;(干货——ObjectName属性的作用,作为标识类型)
2)名称对象:是 javax.management.ObjectName 类的实例。对象名称由两部分组成:域和一个键值对;
public class ObjectName implements Comparable<ObjectName>, QueryExp { //javax.management.ObjectName

3)键与其值是由等号分割的,键值对之间由 分号分割,如,下面是一个有效的对象名称,包含两个键:
myDomain:type=Car,color=blue;

4)ObjectName 实例也表示在 MBean服务器中搜索 MBean实例的属性模式;

4.1)ObjectName实例可以在域部分或键值对部分使用通配符来表示模式,作为模式的 ObjectName实例可以有0个或多个键;

【3】 标准MBean
1)intro: 标准MBean 是最简单的MBean类型。要想通过标准MBean来管理一个java对象,需要执行以下steps:

step1)创建一个接口,该接口的命名规范为: java类名+MBean后缀;如想要管理的java类名为Car,则需要创建命名为
CarMBean的接口;
step2)修改java类,让其实现刚刚创建的 CarMBean接口;
step3)创建一个代理,该代理类必须包含一个 MBeanServer实例;
step4)为MBean创建 ObjectName 实例;
step5)实例化 MBeanServer类;
step6)将 MBean注册到 MBeanServer 中;

2)看个荔枝:下面是一个标准MBean的例子,JMX可管理的类是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.");
}
}


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) {
}
}


3)StandardAgent.main()方法首先会创建 StandardAgent类的一个实例,调用其getMBeanServer()方法,以得到 StandardAgent 中对 MBeanServer实例的一次引用;
StandardAgent agent = new StandardAgent();
MBeanServer mBeanServer = agent.getMBeanServer();

4)然后,它会为 CarMbean实例的创建一个 OBjectgName实例;MBeanServer实例的默认域会作为 ObjectName 实例的域使用。一个名为 type 的键会被添加到域后面。键type 的值是托管资源的完全限定名:
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);

6)接着,main()方法就可以通过CarMBean实例来管理Car对象。它会创建一个名为 colorAttribute 的 Attribute类型的对象,用来表示 Car类的 Color属性,并设置其值为 blue;然后,它再调用 setAttribute()方法,接着,它会通过调用 MBeanServer.invoke()方法来嗲用Car.drive()方法;
// 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);
}

7)运行结果
blue
Baby you can drive my car.

Attention)

A1)我们很想知道,到底为什么需要使用 JMX 来管理 java对象呢?
A2)上面的荔枝中,我们可以通过 StandardAgent 类来直接访问Car对象了;这里的关键问题是可以选择哪些功能需要暴露出来,哪些方法需要对外隐藏;(干货——这里的关键问题是可以选择哪些功能需要暴露出来,哪些方法需要对外隐藏)

【4】模型MBean
1)intro:相比于标准MBean,模型MBean具有更大的灵活性;如果不能修改已有的java类,那么使用模型MBean是不错 的选择;(不再需要为可管理的对象修改java类了 )
2)模型MBean和标准MBean的区别:(干货——模型MBean和标准MBean的区别)

2.1)在使用标准MBean管理资源时,需要定义一个接口;然后让托管资源实现该接口;而使用模型MBean时,不需要定义接口;相反,可以使用 javax.management.modelmbean.ModelMBean 接口来表示模型MBean,只需要实现该接口;
2.2)在JMX 的参考实现中有一个 javax.management.modelmbean.RequiredModelMBean类,是ModelMBean接口的默认实现, 可以实例化 RequiredModelMBean 类或其子类;

3)编写一个模型MBean 的最大挑战是 告诉 ModelMBean对象托管资源的哪些属性和方法可以暴露给代理;可以通过创建 javax.management.modelmbean.ModelMBeanInfo对象来完成这个任务;
4)javax.management.modelmbean.ModelMBeanInfo对象(干货——ModelMBeanInfo对象的作用)

4.1)ModelMBeanInfo对象描述了将会暴露给代理的构造函数,属性,操作甚至是监听器;

5)使用 RequiredModelMBean类作为 ModelMBean的实现,有两种方法可以将 ModelMBean对象与 ModelMBeanInfo对象相关联:

method1)传入一个 ModelMBeanInfo 对象到 RequiredModelBean 对象的构造函数中 ;
method2)调用 RequiredModelMBean 对象的 setModelMBeanInfo()方法,并传入一个 ModelMBeanInfo对象;

6)在创建了 ModelMBean对象后,需要调用ModelMBean接口的 setManagedResource()方法将其与托管资源相关联,该方法的签名如下:
public void setManagedResource(Object mr, String mr_type)  throws MBeanException, RuntimeOperationsException,  InstanceNotFoundException, InvalidTargetObjectTypeException ;

【4.1】MBeanInfo 接口与 ModelMBeanInfo接口
1)javax.management.modelmbean.ModelMBeanInfo 定义源码如下:
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)intro to ModelMBeanInfo接口:该接口描述了要通过MOdelMBean 暴露给代理层的构造函数,属性,方法和监听器;(干货——ModelMBeanInfo接口的作用,JMX提供的默认实现类是ModelMBeanInfoSupport

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);
}
}


【4.2】ModelMBean实例
1)看个荔枝: 该荔枝展示了如何使用模型MBean管理Car对象。

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.


【5】 Commons Modeler库
1)intro:该库是Apache 的 Jakarta项目的一部分,目的是 使编写模型MBean更加方便;实际上,最大的帮助是 不需要再写代码创建 ModelMBeanInfo对象了;(干货——Commons
Modeler库的目的)

2)problem+solution:

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)对于每个MBean,需要写出MBean类和托管资源类的完全限定名,此外还有由  MBean暴露的属性和方法。然后,使用 org.apache.commons.modeler.Registry 实例读取这个XML 文档,并创建一个 MBeanServer实例,在按照mbean描述符文件中的XML 元素创建所有的ManagedBean实例;

3.1)然后,调用MAnagedBean.createMBean()方法创建模型MBean。这之后就是普通的流程了。
3.2)下面介绍mbean描述符文件的格式, 然后讨论Modeler库中的3个重要的类,分别是 Registry类,ManagedBean类 和 BaseModelMBean类;

【5.1】MBean描述符
1)intro:MBean描述符是一个XML文档,该文档描述了 将会由 MBean服务器管理的模型MBean的实例,MBean描述符以下面的头信息开始:


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>


对以上代码的分析(Analysis):

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类名;

【5.2】mbena元素示例
1)在catalina的mbean-descriptors.xml 文件中声明了一系列模型 MBean,该文件包位于 org.apache.catalina.mbeans 包下;其源代码如下:  
<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>

对以上代码的分析(Analysis):mbean元素声明了一个模型MBean,其唯一标识是 MBeanFactory,该MBeanFactory是
org.apache.catalina.mbeans.MBeanFactory 类的一个对象;

【5.3】自己编写一个模型MBean类
1)intro:使用Commons Modeler库,需要在 mbean元素的className属性中指明自定义的模型MBean的类型。默认case下,Commons Modeler库 使用 org.apache.commons.modeler.BaseModelMBean类;
2)有两种cases,其中可能对 BaseModelMBean类进行扩展:

case1)需要覆盖托管资源的属性或方法;

case2)需要添加在托管资源中没有定义的属性或方法;

【5.4】Registry类(org.apche.commons.modeler.Registry)
1)该类定了很多方法,如下:

method1)获取javax.management.MBeanServer 类的一个实例,所以不再需要调用 javax.management.MBeanServerFactory.createMBeanServer()方法了;

method2)使用 loadRegistry() 方法读取 MBean 的描述符文件;

method3)创建一个 ManagedBean 对象,用于创建模型 MBean的实例;

【5.5】ManagedBean
1)intro:ManagedBean 对象:描述了一个模型MBean,该类用于取代 javax.management.MBeanInfo 对象 ;

【5.6】BaseModelMBean
1)org.apache.commons.modeler.BaseModelMBean 类实现了 javax.management.modelmbean.ModelMBean 接口。使用这个类,就不需要用 javax.management.modelmbean.RequiredModelMBean类了;
2)该类用了 resource字段:该字段表示该模型 MBean管理的资源;
public class BaseModelMBean implements ModelMBean, MBeanRegistration { // org.apache.commons.modeler.BaseModelMBean
protected Object resource = null;
}

【5.7】使用 Modeler库API
1)Car类的定义源码
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)使用 Commons Modeler库,不需要使用硬编码的方式,将托管对象的所有属性和方法都写在代码中。相反,可以将他们写在一个 XML文档中,作为 MBean 的描述符文件;

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>


【6】Catalina中的 MBean
1)intro:catalina在org.apache.catalina.mbeans 包中提供了一系列 MBean类;这些 MBean类都直接或间接继承自 org.apache.commons.modeler.BaseModelMBean类;
2)本小姐会讨论tomcat4中的3个最重要的 MBean,分别是 ClassNameMBena类, StandardServerMBean类 和 MBeanFactory类;(干货——tomcat4中最重要的3个MBean)

【6.1】ClassNameMBena类(org.apache.catalina.mbeans.ClassNameMBean)
public class ClassNameMBean extends BaseModelMBean { // org.apache.catalina.mbeans.ClassNameMBean
public ClassNameMBean()
throws MBeanException, RuntimeOperationsException {
super();
}
public String getClassName() {
return (this.resource.getClass().getName());
}
}

对以上代码的分析(Analysis): ClassNameMBena类是 BaseModelMBena的子类,其只写属性 className 在托管资源中不可见;mbeans-descriptors.xml 文件中的很多mbean元素使用该类作为其模型MBean的模型;

【6.2】StandardServerMBean类
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");
}
}
}
}

对以上代码的分析(Analysis):StandardServerMBena类是一种模型MBean,继承自 BaseModelMBean类,并重写了 托管资源的一个方法;

【6.3】MBenaFactory类
public class MBeanFactory extends BaseModelMBean { //org.apache.catalina.mbeans.MBeanFactory.

1)intro:MBenaFactory类的实例是一个工厂对象: 用于创建管理 tomcat 中 各种资源的所有模型mbean;MBeanFactory类还提供 了删除这些MBean的方法;
Attention)org.apache.catalina.mbeans.MBeanFactory 的源码定义会在文末 po出,有兴趣朋友的可以直接跳到文末,该类的方法还是比较重要的,所以po 之;

【6.4】MBeanUtil(org.apache.catlaina.mbeans.MBeanUtil)
1)intro:MBeanUtil类是一个工具类,提供了一些静态方法用于创建各种管理 catalina对象的MBean,删除MBean,以及创建 ObjectName 实例等;
2)看个荔枝: MBeanUtil.createMBean()方法用于创建一个管理 org.apache.catalina.Server 对象的模型MBean;
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);
}

【7】创建catalina的MBean
1)下面介绍一下如何创建 Catalina中的 模型MBean,并使用它们来管理 Catalina中的托管资源;
2)在tomcat的配置文件 server.xml 中,在 Server元素里面定义了如下所示的Listener元素:
<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" />
//......

对以上代码的分析(Analysis):

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());
}
}

}

}


3)在Catalina中,createMBeans()方法用来创建所有的MBean实例。该方法首先会创建 MBeanFactory类的一个实例,也是一个 模型 MBean实例;方法源码定义如下:
protected void createMBeans() { // org.apache.catalina.mbeans.ServerLifecycleListener.createMBeans().
try {
MBeanFactory factory = new MBeanFactory();
createMBeans(factory);
createMBeans(ServerFactory.getServer());

}//......
}

对以上代码的分析(Analysis)

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]);
}
}


Attention)上述createMbeans(Server server)方法调用for 循环中下面的语句遍历 StandardServer实例中所有的Service对象;
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.
}

对createMBeans(services[i]) 方法的分析(Analysis): 

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());
}
//......
}


对以上代码的分析(Analysis):

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类的对象;

【8】 应用程序
1)intro:该应用程序是用来管理 tomcat 的web 应用程序。虽然它很simple,但已足够说明如何使用 Catalina暴露出的MBean。可以列出 Catalina 中所有 ObjectName 实例,以及当前正在运行的所有 Context实例,并删除其中任意一个;

2)利用JMX 管理tomcat 中bean 的应用程序构造

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>


3)访问效果



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: