Chapter 20: JMX-Based Management(第 20 章:基于 JMX 的管理)
Chapter 19 discussed the Manager application. It showed that the ManagerServlet class implemented the ContainerServlet interface to get access to Catalina internal objects. This chapter now shows that managing Tomcat can be achieved more sophisticatedly using the Java Management Extensions (the JMX specification). For those unfamiliar with JMX, a brief introduction is given at the beginning of the chapter. In addition, this chapter explains the Commons Modeler library that Catalina uses to ease the task of writing Managed Beans, the objects used for managing other objects. Examples are offered to make understanding the use of JMX in Tomcat easier.
第19章讨论了Manager应用程序。
它展示了 ManagerServlet
类实现了ContainerServlet接口,以便访问Catalina内部对象。
本章将展示更复杂地使用Java管理扩展(JMX规范)来管理Tomcat。
对于不熟悉JMX的人,本章在开头进行了简要介绍。
此外,本章还解释了Catalina使用的Commons Modeler库,以简化编写管理其他对象的托管Bean的任务。
为了更好地理解在Tomcat中使用JMX的用法,提供了示例。
Introduction to JMX(JMX 简介)
So, if the ContainerServlet interface is good enough for the Manager application to get access to the internal body of Catalina, why should we care about JMX? Because JMX provides much greater flexibility than ContainerServlet. Many server-based applications, such as Tomcat, JBoss, JONAS, Geronimo, and many others, use this cool technology to manage their resources.
如果ContainerServlet接口足够好,可以让Manager应用程序访问Catalina的内部结构,那么我们为什么要关心JMX呢?因为JMX提供了比ContainerServlet更大的灵活性。
许多基于服务器的应用程序,如Tomcat、JBoss、JONAS、Geronimo等,都使用这项很酷的技术来管理它们的资源。
The JMX specification, currently at version 1.2.1, defines an open standard for managing Java objects. For example, Tomcat 4 and 5 use JMX to enable various objects (such as server, host, context, valve, and so on) in the servlet container to be flexibly and easily managed by management applications. The developers of Tomcat even made the effort to write the Admin application that acts as a management application.
JMX规范目前处于1.2.1版本,定义了一种管理Java对象的开放标准。
例如,Tomcat 4和5使用JMX来使得servlet容器中的各种对象(如服务器、主机、上下文、阀门等)能够灵活、轻松地由管理应用程序管理。
Tomcat的开发人员甚至还费心编写了一个作为管理应用程序的Admin应用程序。
A Java object that can be managed by JMX-compliant manager application is said to be a JMX manageable resource. In fact, a JMX manageable resource can also be an application, an implementation or a service, a device, a user, and so forth. A JMX manageable resource is written in Java or provides a Java wrapper.
一个可以由符合JMX管理器应用程序的管理的Java对象被称为JMX可管理资源。
实际上,JMX可管理资源也可以是一个应用程序、一个实现或服务、一个设备、一个用户等等。
JMX可管理资源是用Java编写的或提供Java包装器的。
For a Java object to be a JMX manageable resource, you must create another object called Managed Bean or MBean. The org.apache.catalina.mbeans package contains a number of MBeans. ConnectorMBean, StandardEngineMBean, StandardHostMBean, StandardContextMBean are examples of the Managed Beans in this package. From their name you can guess that the ConnectMBean class is used to manage a connector, the StandardContextMBean class is for managing an org.apache.catalina.core.StandardContext instance, and so on. Of course, you can also write an MBean that manages more than one Java object if you want to.
要使一个Java对象成为JMX可管理资源,您必须创建另一个称为Managed Bean或MBean的对象。
org.apache.catalina.mbeans包中包含了许多MBean。ConnectorMBean、StandardEngineMBean、StandardHostMBean、StandardContextMBean是该包中的Managed Bean的示例。
从它们的名称可以猜到,ConnectMBean类用于管理连接器,StandardContextMBean类用于管理org.apache.catalina.core.StandardContext实例,等等。
当然,如果需要,您也可以编写一个管理多个Java对象的MBean。
An MBean exposes the properties and methods of the Java object(s) it manages the management application. The management application itself does not have access to the managed Java objects directly. Therefore, you can choose any property and or method of a Java object that should be callable by the management application.
一个MBean向管理应用程序公开它管理的Java对象的属性和方法。管理应用程序本身不能直接访问被管理的Java对象。因此,您可以选择任何一个Java对象的属性和/或方法,使其可被管理应用程序调用。
Once you have an MBean class, you need to instantiate it and register it with another Java object referred to as the MBean server. The MBean server is a central registry for all the MBeans in an application. The management application accesses the MBeans through the MBean server. Drawing an analogy between JMX and a servlet application, the management application is equivalent to a web browser. The MBean server is like a servlet container; it provides access to the managed-resources to the client (the management application). The MBeans are servlets or JSP pages. Just like the web browser never touches a servlet/JSP page directly but only through a servlet container, a management application accesses the MBeans through the MBean server.
一旦您有了一个MBean类,您需要实例化它,并将其注册到另一个被称为MBean服务器的Java对象中。
MBean服务器是一个应用程序中所有MBean的中央注册表。管理应用程序通过MBean服务器访问MBeans。将JMX与servlet应用程序进行类比,管理应用程序相当于Web浏览器。
MBean服务器类似于servlet容器;它为客户端(管理应用程序)提供对被管理资源的访问。MBeans就像servlet或JSP页面。
就像Web浏览器永远不直接访问servlet/JSP页面,而是通过servlet容器,管理应用程序通过MBean服务器访问MBeans。
There are four types of MBeans: standard, dynamic, open, and model. Standard MBeans are the easiest to write among the four, but offer the least flexibility. The other three come with more flexibility and we're particularly interested in model MBeans because Catalina uses this type of MBeans. Standard MBeans are discussed next to give you the look and feel of writing an MBean. Afterwards, there is a discussion of model MBeans. We skip the dynamic and open MBeans because they are not relevant to this chapter. Interested readers are referred to the JMX 1.2.1 specification document for further details.
有四种类型的MBean:标准、动态、开放和模型。在这四种类型中,标准MBean是最容易编写的,但提供的灵活性最少。
其他三种类型提供更大的灵活性,我们特别关注模型MBean,因为Catalina使用这种类型的MBean。
接下来将讨论标准MBean,以便让您了解编写MBean的外观和感觉。然后,将讨论模型MBean。
我们跳过动态和开放MBean,因为它们与本章不相关。有兴趣的读者可以参考JMX 1.2.1规范文档以获取更多细节。
Architecturally, the JMX specification is divided into three levels, the instrumentation level, the agent level, and the distributed services level. The MBean server resides in the agent level and the MBeans in the instrumentation level. The distributed services level will be covered in the future version of the JMX specification.
从架构上讲,JMX规范分为三个级别:
- 仪器级别
- 代理级别
- 分布式服务级别
MBean服务器位于代理级别,MBeans位于仪器级别。分布式服务级别将在未来版本的JMX规范中介绍。
The instrumentation level of the specification defines the standard for writing JMX manageable resources, i.e. how to write MBeans. The agent level provides a specification for creating agents. An agent encapsulates an MBean server and services for handling MBeans. Agents and MBeans they manage normally reside in the same Java Virtual Machine. Because the JMX specification comes with a reference implementation, you do not need to write an MBean server of your own. The reference implementation provides a way of creating a default MBean server.
规范的仪器级别定义了编写JMX可管理资源的标准,即如何编写MBeans。
代理级别提供了创建代理的规范。代理封装了一个MBean服务器和处理MBeans的服务。
代理和它们管理的MBeans通常驻留在同一个Java虚拟机中。
由于JMX规范附带了一个参考实现,您不需要编写自己的MBean服务器。参考实现提供了一种创建默认MBean服务器的方法。
Note Download the specification and reference implementation from http://java.sun.com/products/JavaManagement/download.html. MX4J, an open source version of JMX whose library is included in the software accompanying this book, is available from http://mx4j.sourceforge.net
注意:从http://java.sun.com/products/JavaManagement/download.html下载规范和参考实现。MX4J是JMX的开源版本,其库包含在附带本书的软件中,可从http://mx4j.sourceforge.net获取。
Warning The zip file that accompanies this book contains the mx4j.jar file that packages the version 2.0 beta 1 of MX4J, replacing the mx4j-jmx.jar file included in Tomcat 4.1.12. This was done in order for you to use the more recent version of JMX (version 1.2.1).
警告:随本书附带的zip文件包含mx4j.jar文件,该文件打包了MX4J的2.0 beta 1版本,取代了Tomcat 4.1.12中包含的mx4j-jmx.jar文件。
这样做是为了让您使用更新的JMX版本(1.2.1版)。
The JMX API(JMX API)
The reference implementation consists of a core Java library in the javax.management package and other packages specific to certain areas of JMX programming. This section discusses some of the more important types in the API.
参考实现由javax.management包中的核心Java库和其他特定于某些JMX编程领域的包组成。
本节讨论了API中一些较重要的类型。
MBeanServer
The javax.management.MBeanServer interface represents an MBean server. To create an instance of MBeanServer, simply use one of the methods in the javax.management.MBeanServerFactory class, such as the createMBean method.
javax.management.MBeanServer接口表示一个MBean服务器。
要创建MBeanServer的实例,只需使用javax.management.MBeanServerFactory类中的方法之一,例如createMBean方法。
To register an MBean with an MBeanServer, call the registerMBean method on the MBeanServer instance. The following is the signature of the registerMBean method.
要将MBean注册到MBeanServer中,调用MBeanServer实例上的registerMBean方法。
以下是registerMBean方法的签名。
public ObjectInstance registerMBean(java.lang.Object object,
ObjectName name) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException
To the registerMBean method you pass the MBean instance you want to register and the ObjectName instance. An ObjectName instance is like a key in a HashMap; it uniquely identifies an MBean. The registerMBean method returns an ObjectInstance. The javax.management.ObjectInstance class encapsulates an object name of an MBean and its class name.
通过registerMBean方法,您需要传递要注册的MBean实例和ObjectName实例。
ObjectName实例类似于HashMap中的键;它唯一标识一个MBean。
registerMBean方法返回一个ObjectInstance。javax.management.ObjectInstance类封装了一个MBean的对象名称和其类名称。
To retrieve an MBean or a set of MBeans matching a pattern, the MBeanServer interface provides two methods: queryNames and queryMBeans. The queryNames method returns a java.util.Set containing the object names of the MBeans matching the specified pattern object name. Here is the signature of the queryName method:
要检索匹配模式的MBean或一组MBean,MBeanServer接口提供了两种方法:queryNames和queryMBeans。queryNames方法返回一个包含与指定模式对象名称匹配的MBean对象名称的java.util.Set。
以下是queryName方法的签名:
public java.util.Set queryNames(ObjectName name, QueryExp query)
The query argument specifies the filtering criteria.
查询参数指定过滤标准。
If the name argument is null or no domain and key properties are specified, all the ObjectName instances of the registered MBeans will be returned. If the query is null, no filtering is applied.
如果 name 参数为空或未指定域和键属性,则将返回已注册 MBeans 的所有 ObjectName 实例。如果查询参数为空,则不会应用过滤功能。
The queryMBeans method is similar to queryNames. However, it returns a java.util.Set containing ObjectInstance objects for the selected MBeans. The queryMBeans method has the following signature:
queryMBeans 方法与 queryNames 类似。
不过,它返回的是一个 java.util.Set 集合,其中包含所选 MBeans 的 ObjectInstance 对象。queryMBeans 方法的签名如下:
public java.util.Set queryMBeans(ObjectName name, QueryExp query)
Once you have the object name of the MBean you want, you can manipulate the property of the managed resource or invoke its method exposed in the MBean.
一旦你获得了想要的 MBean 的对象名称,你就可以操作托管资源的属性或调用 MBean 中公开的方法。
You can call any method of the registered MBeans by calling the MBeanServer interface's invoke method. The MBeanServer interface's getAttribute and setAttribute methods are used for getting and setting a property of a registered MBean.
你可以通过调用 MBeanServer 接口的 invoke 方法来调用已注册的 MBeans 的任何方法。
MBeanServer 接口的 getAttribute 和 setAttribute 方法用于获取和设置已注册 MBean 的属性。
ObjectName
An MBean server is a registry for MBeans. Each of the MBeans in an MBean server is uniquely identified by an object name, just like an entry in a HashMap is uniquely identified by a key.
MBean 服务器是 MBeans 的注册表。
MBean 服务器中的每个 MBean 都由对象名称唯一标识,就像 HashMap 中的条目由键唯一标识一样。
An object name is represented by the javax.management.ObjectName class. An object name consists of two parts: a domain and a set of key/value pairs. A domain is a string, and can be a blank string. In an object name, the domain is followed by a colon and one or more key/value pairs. A key is a non-blank string that may not contain any of the following characters: equal sign, comma, colon, asterisk, and question mark. The same key may only occur once in an object name.
对象名称由 javax.management.ObjectName 类表示。
对象名称由两部分组成:域和一组键/值对。域是一个字符串,可以是空字符串。在对象名称中,域后面跟着一个冒号和一个或多个键/值对。
键是一个非空字符串,不得包含以下任何字符:等号、逗号、冒号、星号和问号。同一个键在对象名称中只能出现一次。
A key and its value are separated by an equal sign, and two key/value pairs are separated by a comma. For example, the following is a valid object name with two keys:
键及其值之间用等号分隔,两个键/值对之间用逗号分隔。
例如,以下是一个具有两个键的有效对象名称:
myDomain:type=Car,color=blue
An ObjectName instance can also represent a property pattern for searching MBeans in an MBean server. An ObjectName that is a pattern uses a wildcard in its domain part or key/value pairs. A pattern ObjectName may have zero or more keys.
ObjectName 实例还可以表示用于在 MBean 服务器中搜索 MBeans 的属性模式。
模式 ObjectName 在其域部分或键/值对中使用通配符。模式 ObjectName 可能具有零个或多个键。
Standard MBeans(标准 MBeans)
Standard MBeans are the simplest MBeans. To manage a Java object using a standard MBean, here is what you need to do:
标准MBean是最简单的MBean。
要使用标准MBean管理一个Java对象,需要按照以下步骤进行操作:
- Create an interface named after your Java class plus the suffix MBean. For example, if the Java class you want to manage is called Car, the interface is called CarMBean.
- Modify your Java class so that it implements the interface you've created.
- Create an agent. The agent class must contain an MBeanServer.
- Create an ObjectName for your MBean.
- Instantiate the MBeanServer.
- Register the MBean in the MBeanServer.
- 创建一个以您的Java类名称加上后缀MBean的接口。例如,如果要管理的Java类名为Car,则接口名为CarMBean。
- 修改您的Java类,使其实现您创建的接口。
- 创建一个代理类。该代理类必须包含一个MBeanServer。
- 为您的MBean创建一个ObjectName。
- 实例化MBeanServer。
- 将MBean注册到MBeanServer中。
The standard MBeans are the easiest to write, but using them requires your classes be modified. While modifying the classes is okay in some projects, in others (especially when the number of classes is high) this is not acceptable. Other types of MBeans allow you to manage your objects without modifying your classes.
标准MBean是编写最简单的MBean,但使用它们需要修改您的类。
在某些项目中修改类是可以接受的,但在其他项目中(特别是类数量较多时)这是不可接受的。
其他类型的MBean可以让您在不修改类的情况下管理对象。
As an example of a standard MBean, consider the following Car class that you want to be JMX-manageable:
以一个标准MBean的例子来说明,考虑以下要使其能够通过JMX管理的Car类:
package ex20.pyrmont.standardmbeantest;
package ex20.pyrmont.standardmbeantest;
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.");
}
}
The first step you need to take is modify it so that it implements the CarMBean interface. The new Car class is given in Listing 20.1:
您需要做的第一步是修改该类,使其实现 CarMBean 接口。新的 Car 类如清单 20.1 所示:
Listing 20.1: The modified Car class
清单 20.1:修改后的 Car 类
package ex20.pyrmont.standardmbeantest;
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.");
}
}
Now, create the CarMBean interface in Listing 20.2
现在,创建清单 20.2 中的 CarMBean 接口
Listing 20.2: The CarMBean interface
清单 20.2:CarMBean 接口
package ex20.pyrmont.standardmbeantest;
public interface CarMBean {
public String getColor();
public void setColor(String color);
public void drive();
}
Basically, in the interface you declare all the methods that you want the Car class to expose. In this example, the CarMBean interface lists all the methods in the Car class. If, say, you don't want the drive method to be available to the management application, all you need to do is remove its definition from the CarMBean interface.
基本上,在接口中声明了你希望 Car 类公开的所有方法。
在这个例子中,CarMBean 接口列出了 Car 类中的所有方法。
如果你不想让驾驶方法对管理应用程序可用,你只需要从 CarMBean 接口中移除它的定义。
Finally, Listing 20.3 offers the StandardAgent class that is used to create a standard MBean and manage the Car object
最后,第20.3节提供了用于创建标准 MBean 并管理 Car 对象的 StandardAgent 类。
Listing 20.3: The StandardAgent class
第20.3节:StandardAgent 类
package ex20.pyrmont.standardmbeantest;
import javax.management.Attribute;
import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
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();
MBeanServer mBeanServer = agent.getMBeanServer();
String domain = mBeanServer.getDefaultDomain();
String managedResourceClassName =
"ex20.pyrmont.standardmbeantest.Car";
ObjectName objectName = agent.createObjectName(domain + ":type=" +
managedResourceClassName);
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);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
The StandardAgent class is an agent that will instantiate an MBean server and use it to register a CarMBean. The first thing to note is the mBeanServer variable, to which the StandardAgent class's constructor assigns an MBeanServer. The constructor calls the createMBeanServer method of the MBeanServerFactory class.
StandardAgent 类是一个将实例化 MBean 服务器并用于注册 CarMBean 的代理。
首先要注意的是 mBeanServer 变量,StandardAgent 类的构造函数会为该变量分配一个 MBeanServer。
构造函数调用 MBeanServerFactory 类的 createMBeanServer 方法。
public StandardAgent() {
mBeanServer = MBeanServerFactory.createMBeanServer();
}
The createMBeanServer method returns a default MBeanServer object implemented by the JMX reference implementation. An advanced JMX programmer may wish to provide his/her own MBeanServer implementation. For this book, however, we're not interested in doing so.
createMBeanServer方法返回由JMX参考实现实现的默认MBeanServer对象。
高级的JMX程序员可能希望提供自己的MBeanServer实现。然而,在本书中,我们对此不感兴趣。
The createObjectName method in the StandardAgent class in Listing 20.3 returns an instance of ObjectName based on the String argument passed to the method. The createStandardMBean method in StandardAgent calls the createMBean method of MBeanServer. The createMBean method accepts the class name of the managed resource and the ObjectName instance that uniquely identifies the created MBean for the managed resource. The createMBean method also registers the created MBean in the MBeanServer. Because a standard MBean follows a certain naming convention, you don't need to supply the MBean type name to the createMBean method. If the managed resource's class name is Car, then its MBean will be CarMBean.
StandardAgent类中的createObjectName方法在Listing 20.3中根据传递给该方法的字符串参数返回一个ObjectName实例。
StandardAgent中的createStandardMBean方法调用MBeanServer的createMBean方法。
createMBean方法接受托管资源的类名和唯一标识创建的MBean的ObjectName实例。
createMBean方法还在MBeanServer中注册创建的MBean。
由于标准MBean遵循特定的命名约定,您不需要向createMBean方法提供MBean类型名称。
如果托管资源的类名是Car,则其MBean将是CarMBean。
The main method of StandardAgent starts off by creating an instance of StandardAgent and calls its getMBeanServer method to obtain a reference to the MBeanServer instance inside the StandardAgent.
StandardAgent的main方法首先创建StandardAgent的实例,并调用其getMBeanServer方法以获取StandardAgent内部的MBeanServer实例的引用。
StandardAgent agent = new StandardAgent();
MBeanServer mBeanServer = agent.getMBeanServer();
It then creates an ObjectName for the CarMBean. The MBeanServer's default domain is used as the domain for the ObjectName. A key named type is appended to the domain. The value for type is the fully qualified name of the managed resource.
然后,它会为 CarMBean 创建一个 ObjectName。
MBeanServer 的默认域被用作 ObjectName 的域。名为 type 的键被附加到域中。
type 的值是受管资源的全称。
String domain = mBeanServer.getDefaultDomain();
String managedResourceClassName =
"ex20.pyrmont.standardmbeantest.Car";
ObjectName objectName = agent.createObjectName(domain + ":type=" +
managedResourceClassName);
The main method then calls the createStandardBean method, passing the object name and the managed resource class name.
然后,main 方法调用 createStandardBean 方法,并传递对象名称和托管资源类名称。
agent.createStandardBean(objectName, managedResourceClassName);
Next, the main method manages the Car object through the CarMBean instance. It creates an Attribute object called colorAttribute to represent the Color attribute and sets the value to blue. It then invokes the setAttribute method passing the objectName and colorAttribute. It then invokes the drive method using the invoke method on the MBeanServer object.
接下来,主方法通过CarMBean实例来管理Car对象。
它创建了一个名为colorAttribute的Attribute对象来表示颜色属性,并将值设置为蓝色。
然后,它通过传递objectName和colorAttribute来调用setAttribute方法。
然后,它使用MBeanServer对象上的invoke方法来调用drive方法。
Model MBeans(MBeans 模式)
Model MBeans provide flexibility. They are harder to program than standard MBeans, but you do not need to modify your Java classes for the objects to be manageable. Using model MBeans is highly preferable if modifying the existing classes is not an option.
Model MBeans提供了灵活性。
它们比标准MBeans更难编程,但您无需修改Java类即可管理对象。
如果修改现有类不是一个选项,那么使用模型MBeans是非常可取的。
Using model MBeans is different from using standard MBeans. When employing a standard MBean to manage your resource, you write an interface that must be implemented by the managed resource. When using a model MBean, you do not write any interface. Instead, the javax.management.modelmbean.ModelMBean interface is provided for you that represents a model MBean. You just need to have an implementation for this interface. Luckily, JMX comes with the javax.management.modelmbean.RequiredModelMBean class, the default implementation of ModelMBean. You can instantiate the RequiredModelMBean class or its subclass.
使用模型MBeans与使用标准MBeans不同。
当使用标准MBean来管理资源时,您需要编写一个由受管资源实现的接口。而使用模型MBean时,您不需要编写任何接口。相反,javax.management.modelmbean.ModelMBean接口为您提供了一个表示模型MBean的接口。您只需要为此接口编写一个实现即可。
幸运的是,JMX提供了javax.management.modelmbean.RequiredModelMBean类,它是ModelMBean的默认实现。您可以实例化RequiredModelMBean类或其子类。
Note Other implementation classes for the ModelMBean interface are also possible. For example, the Commons Modeler library, which we will discuss in the next section, has its own implementation class that does not extend RequiredModelMBean.
注意,ModelMBean接口的其他实现类也是可能的。
例如,我们将在下一节中讨论的Commons Modeler库有自己的实现类,它不继承RequiredModelMBean。
The greatest challenge in writing a model MBean is telling your ModelMBean object which attributes and operations in the managed resource should be exposed to an agent. You achieve this by creating a javax.management.modelmbean.ModelMBeanInfo object. A ModelMBeanInfo object describes the constructors, attributes, operations, and event listeners exposed to an agent. Constructing a ModelMBeanInfo object can be a tedious task (see the example in this section), but once you have one, you just need to associate it with your ModelMBean object.
编写模型MBean的最大挑战是告诉您的ModelMBean对象应该将受管资源的哪些属性和操作暴露给代理。
您可以通过创建一个javax.management.modelmbean.ModelMBeanInfo对象来实现这一点。ModelMBeanInfo对象描述了构造函数、属性、操作和事件监听器对代理可见。
构造一个ModelMBeanInfo对象可能是一项繁琐的任务(请参见本节的示例),但一旦拥有了一个,您只需要将其与您的ModelMBean对象关联起来即可。
Using RequiredModelMBean as your ModelMBean implementation, there are two ways of associating your ModelMBean with a ModelMBeanInfo:
使用RequiredModelMBean作为您的ModelMBean实现,有两种将您的ModelMBean与ModelMBeanInfo关联的方式:
- By passing the ModelMBeanInfo object to the RequiredModelMBean constructor.
- By passing the ModelMBeanInfo object to the setModelMBeanInfo method on the RequiredModelMBean object.
After constructing a ModelMBean, you must associate your managed resource with it
by calling the setManagedResource method of the ModelMBean interface. This
method has the following signature:
public void setManagedResource(java.lang.Object managedResource, java.lang.String managedResourceType) throws MBeanException, RuntimeOperationsException, InstanceNotFoundException, InvalidTargetObjectTypeException
The value of the managedResourceType argument can be one of the following: ObjectReference, Handle, IOR, EJBHandle, or RMIReference. Currently, only ObjectReference is supported.
Then, of course, you still have to create an ObjectName and register the model MBean with the MBean server.
This section provides an example of using a model MBean with the same Car object as the one used in the standard MBean example. Before we discuss the example, however, let's look at the ModelMBeanInfo interface whose instance describes the attributes and operations that your managed resource will expose.
MBeanInfo and ModelMBeanInfo(MBeanInfo 和 ModelMBeanInfo)
The javax.management.mbean.ModelMBeanInfo interface describes the constructors, attributes, operations, and listeners exposed by a ModelMBean. A constructor is represented by the javax.management.modelmbean.ModelMBeanConstructorInfo class, an attribute by the javax.management.modelmbean.ModelMBeanAttributeInfo class, an operation by the javax.management.modelmbean.ModelMBeanOperationInfo class, and a listener by the javax.management.modelmbean.ModelMBeanNotificationInfo class. In this chapter, we're only interested in the attributes and operations.
javax.management.mbean.ModelMBeanInfo接口描述了ModelMBean所暴露的构造函数、属性、操作和监听器。javax.management.modelmbean.ModelMBeanConstructorInfo类表示构造函数,javax.management.modelmbean.ModelMBeanAttributeInfo类表示属性,javax.management.modelmbean.ModelMBeanOperationInfo类表示操作,javax.management.modelmbean.ModelMBeanNotificationInfo类表示监听器。
在本章中,我们只关注属性和操作。
JMX provides a default implementation of ModelMBeanInfo: the javax.management.modelmbean.ModelMBeanInfoSupport class. Here is the signature of the ModelMBeanInfoSupport class's constructor that we will use in this example:
JMX提供了ModelMBeanInfo的默认实现:javax.management.modelmbean.ModelMBeanInfoSupport类。
以下是我们在本示例中将使用的ModelMBeanInfoSupport类构造函数的签名:
public ModelMBeanInfoSupport(java.lang.String className, java.lang.String description, ModelMBeanAttributeInfo[] attributes, ModelMBeanConstructorInfo[] constructors, ModelMBeanOperationInfo[] operations, ModelMBeanNotificationInfo[] notifications)
You construct a ModelMBeanAttributeInfo object by using its constructor:
您可以使用以下构造函数创建ModelMBeanAttributeInfo对象:
public ModelMBeanAttributeInfo(java.lang.String name,
java.lang.String type, java.lang.String description,
boolean isReadable, boolean isWritable,
boolean isIs, Descriptor descriptor)
throws RuntimeOperationsException
Here is the list of parameters:
以下是参数列表:
- name. The name of the attribute
- type. The type or class name of the attribute
- description. The description of the attribute.
- isReadable. true if the attribute has a getter method, false otherwise.
- isWritable. true if the attribute has a setter method, false otherwise.
- isIs. true if the attribute has an is getter, false otherwise.
- descriptor. An instance of Descriptor containing the appropriate metadata for
this instance of the Attribute. If it is null then a default descriptor will be
created. - name:属性的名称
- type:属性的类型或类名
- description:属性的描述
- isReadable:如果属性有getter方法,则为true;否则为false
- isWritable:如果属性有setter方法,则为true;否则为false
- isIs:如果属性有is getter方法,则为true;否则为false
- descriptor:包含此属性实例的适当元数据的Descriptor实例。如果为null,则将创建一个默认的描述符。
You create a ModelMBeanOperationInfo object using the following constructor:
您可以使用以下构造函数创建ModelMBeanOperationInfo对象:
public ModelMBeanOperationInfo(java.lang.String name, java.lang.String description, MBeanParameterInfo[] signature, java.lang.String type, int impact, Descriptor) throws RuntimeOperationsException
Here is the list of parameters:
以下是参数列表:
- name. The name of the method.
- description. The description of the operation.
- signature, an array of MBeanParameterInfo objects describing the parameters of the method.
- type. The type of the method's return value.
- impact. The impact of the method. The value is one of the following: INFO, ACTION, ACTION_INFO, UNKNOWN.
- descriptor. An instance of Descriptor containing the appropriate metadata, for this instance of the MBeanOperationInfo.
- name:方法的名称
- description:方法的描述
- signature:描述方法参数的MBeanParameterInfo对象数组
- type:方法的返回值类型
- impact:方法的影响。值为以下之一:INFO、ACTION、ACTION_INFO、UNKNOWN
- descriptor:包含此MBeanOperationInfo实例的适当元数据的Descriptor实例。
ModelMBean Example( ModelMBean 示例)
This example shows how to use a model MBean to manage a Car object whose class is presented in Listing 20.4.
本例展示了如何使用模型 MBean 来管理 "汽车 "对象,其类如清单 20.4 所示。
Listing 20.4: The Car class
清单 20.4:汽车类
package ex20.pyrmont.modelmbeantest1;
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.");
}
}
For a model MBean, you don't need to write an interface as in the case of a standard MBean. You simply instantiate the RequiredMBean class. Listing 20.5 provides the ModelAgent class that is used to create the MBean and manage a Car object.
对于模型 MBean,您不需要像编写标准 MBean 那样编写接口。
您只需实例化 RequiredMBean 类。清单 20.5 提供了用于创建 MBean 和管理 Car 对象的 ModelAgent 类。
Listing 20.5: The ModelAgent class
清单 20.5:ModelAgent 类
package ex20.pyrmont.modelmbeantest1;
import javax.management.Attribute;
import javax.management.Descriptor;
import javax.management.MalformedObjectNameException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.ModelMBean;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;
public class ModelAgent {
private String MANAGED_CLASS_NAME =
"ex20.pyrmont.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();
MBeanServer mBeanServer = agent.getMBeanServer();
Car car = new Car();
String domain = mBeanServer.getDefaultDomain();
ObjectName objectName = agent.createObjectName(domain +
":type=MyCar");
String mBeanName = "myMBean";
ModelMBean modelMBean = agent.createMBean(objectName, mBeanName);
try {
modelMBean.setManagedResource(car, "ObjectReference");
mBeanServer.registerMBean(modelMBean, objectName);
}
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);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
As you can see, writing model MBeans requires a lot of work, especially in declaring all the attributes and operations exposed by a managed resource. The next section will look at the Commons Modeler library that helps you write model MBeans faster.
正如您所见,编写模型 MBeans 需要大量工作,特别是在声明受托资源公开的所有属性和操作方面。
下一节将介绍 Commons Modeler 库,它可以帮助您更快地编写模型 MBeans。
Commons Modeler( 共用建模器)
The Commons Modeler library is part of the Apache Software Foundation's Jakarta project. It provides easy ways of writing model MBeans. The greatest help you can get from it is the fact that you don't need to write code to create a ModelMBeanInfo object.
Commons Modeler 库是 Apache 软件基金会的 Jakarta 项目的一部分。
它提供了编写模型 MBeans 的简便方法。
您可以从中获得的最大帮助是,您无需编写代码来创建 ModelMBeanInfo 对象。
Recall from the previous example that to construct a RequiredModelMBean instance, you need to create a ModelMBeanInfo object that you pass to the RequiredModelMBean class's constructor:
从前面的例子中可以回忆起,要构建一个RequiredModelMBean实例,你需要创建一个ModelMBeanInfo对象,并将其传递给RequiredModelMBean类的构造函数。
ModelMBeanInfo mBeanInfo = createModelMBeanInfo(objectName,
mbeanName);
RequiredModelMBean modelMBean = null;
try {
modelMBean = new RequiredModelMBean(mBeanInfo);
}
...
The Commons Modeler library is part of the Apache Software Foundation's Jakarta project. It provides easy ways of writing model MBeans. The greatest help you can get from it is the fact that you don't need to write code to create a ModelMBeanInfo object.
Commons Modeler库是Apache软件基金会的Jakarta项目的一部分。
它提供了编写模型MBean的简单方式。
它最大的帮助在于你不需要编写代码来创建一个ModelMBeanInfo对象。
Recall from the previous example that to construct a RequiredModelMBean instance, you need to create a ModelMBeanInfo object that you pass to the RequiredModelMBean class's constructor:
回想一下前面的例子,要构造一个RequiredModelMBean实例,你需要创建一个ModelMBeanInfo对象,然后将其传递给RequiredModelMBean类的构造函数:
MBean Descriptor(MBean 描述符)
An MBean descriptor is an XML document that describes the model MBeans managed by the MBean server. An MBean descriptor starts with the following header:
MBean描述符是一个XML文档,用于描述MBean服务器管理的模型MBeans。
MBean描述符以以下标头开始:
It is followed by the mbeans-descriptors root element:
其后是 mbeans-descriptors 根元素:
...
Inside the opening and closing mbeans-descriptors tags are mbean elements, each of which represents a model MBean. The mbean element can contain elements that represent attributes, operations, constructors, and notification. The following subsections discuss three elements that you need to understand Tomcat's MBean descriptor.
在开放和关闭的mbeans-descriptors标签内部,包含着mbean元素,每个元素代表一个模型MBean。
mbean元素可以包含代表属性、操作、构造函数和通知的元素。
接下来的小节将讨论三个元素,你需要了解Tomcat的MBean描述符。
mbean
An mbean element describes a model MBean and includes the information to construct the corresponding ModelMBeanInfo object. The mbean element has the following definition:
mbean 元素描述一个模型 MBean,并包含用于构建相应 ModelMBeanInfo 对象的信息。
mbean 元素的定义如下:
The mbean element definition specifies that an mbean element can contain an optional descriptor element, zero or more attribute elements, zero or more constructor elements, zero or more notification elements, and zero or more operation elements.
mbean元素定义指定mbean元素可以包含一个可选的描述符元素,零个或多个属性元素,零个或多个构造函数元素,零个或多个通知元素以及零个或多个操作元素。
An mbean element can have the following attributes:
mbean元素可以具有以下属性:
- className. Fully qualified Java class name of the ModelMBean implementation. If this attribute is not present, the org.apache.commons.modeler.BaseModelMBean will be used.
- description. A description of this model MBean.
- domain. The MBean server's domain in which the ModelMBean created by this managed bean should be registered, when creating its ObjectName.
- group. Optional name of a "grouping classification" that can be used to select groups of similar MBean implementation classes.
- name. A name that uniquely identifies this model MBean. Normally, the base class name of the corresponding server component is used.
- type. Fully qualified Java class name of the managed resource implementation class.
className
.ModelMBean
实现的完全限定Java类名。- 如果没有提供此属性,则将使用
org.apache.commons.modeler.BaseModelMBean
。
- 如果没有提供此属性,则将使用
- description. 此模型MBean的描述。
- domain. 创建由该托管bean创建的ModelMBean时,应将其注册到的MBean服务器的域。
- group. 可选的“分组分类”的名称,可用于选择相似MBean实现类的组。
- name. 唯一标识此模型MBean的名称。通常使用相应服务器组件的基类名称。
- type. 托管资源实现类的完全限定Java类名。
attribute
You use the attribute element to describe a JavaBeans property of an MBean. The attribute element can have an optional descriptor element and can have the following attributes.
你可以使用attribute元素来描述MBean的JavaBeans属性。attribute元素可以包含一个可选的descriptor元素,并且可以具有以下属性。
- description. A description of this attribute.
- displayName. The display name of this attribute.
- getMethod. The getter method of the property represented by the attributeelement.
- is. A boolean value indicating whether or not this attribute is a boolean with an is getter method. By default, the value of the is attribute is false.
- name. The name of this JavaBeans property.
- readable. A boolean value indicating whether or not this attribute is readable by management applications. By default, the value of readable is true.
- setMethod. The setter method of the property represented by this attributeelement.
- type. The fully qualified Java class name of this attribute.
- writeable. A boolean value indicating whether or not this attribute can be written by management applications. By default, this is set to true.
- description。对此属性的描述。
- displayName。此属性的显示名称。
- getMethod。由attribute元素表示的属性的getter方法。
- is。一个布尔值,指示此属性是否具有一个is getter方法。默认情况下,is属性的值为false。
- name。此JavaBeans属性的名称。
- readable。一个布尔值,指示管理应用程序是否可以读取此属性。默认情况下,readable的值为true。
- setMethod。由attribute元素表示的属性的setter方法。
- type。此属性的完全限定的Java类名称。
writeable。一个布尔值,指示管理应用程序是否可以写入此属性。默认情况下,此值为true。
operation
The operation element describes a public method of the model MBean exposed to management applications. It can have zero or more parameter subelements and the following attributes:
操作元素描述了暴露给管理应用程序的模型 MBean 的公共方法。它可以具有零个或多个参数子元素和以下属性:
- description. The description of this operation.
- impact. This attribute indicates the impact of this method. The possible values are ACTION (write like), ACTION-INFO (write+read like), INFO (read like), or UNKNOWN.
- name. The name of this public method.
- returnType. The fully qualified Java class name of the return type of this method.
- description:此操作的描述。
- impact:此方法的影响。可能的值有 ACTION(类似写操作),ACTION-INFO(类似写操作和读操作),INFO(类似读操作)或 UNKNOWN。
- name:此公共方法的名称。
returnType:此方法返回类型的完全限定 Java 类名。
parameter
The parameter element describes a parameter passed to a constructor or an operation. It can have the following attributes:
参数元素描述传递给构造函数或操作的参数。它可以有以下属性:
- description. The description of this parameter.
- name. The name of this parameter.
- type. The fully qualified Java class name of this parameter.
- description(描述)。该参数的描述。
- name(名称)。该参数的名称。
type(类型)。此参数的完整 Java 类名。
Example mbean Element(mbean 元素示例)
Catalina comes with a number of model MBeans that are all declared in the mbean-descriptors.xml file in the org.apache.catalina.mbeans package. Listing 20.6 offers the declaration of the StandardServer MBean in Tomcat 4.
Catalina提供了一些模型MBean,这些MBean都在org.apache.catalina.mbeans包的mbean-descriptors.xml文件中声明。
图表20.6展示了Tomcat 4中StandardServer MBean的声明。
Listing 20.6: The declaration of the StandardServer MBean
清单 20.6:StandardServer MBean 的声明
The mbean element in Listing 20.6 declares a model MBean uniquely identified as StandardServer. This MBean is represented by the org.apache.catalina.mbeans.StandardServerMBean and manages an instance of org.apache.catalina.core.StandardServer. The domain is Catalina and the group is Server.
在第20.6节的代码中,mbean元素声明了一个被唯一标识为StandardServer的模型MBean。这个MBean由org.apache.catalina.mbeans.StandardServerMBean表示,并管理着一个org.apache.catalina.core.StandardServer的实例。域名是Catalina,组名是Server。
There are four properties exposed by the model MBean: debug, managedResource, port, and shutdown, as described by the four attribute elements nested inside the mbean element. The MBean also exposes one method, store, which is described by the operation element.
模型MBean公开了四个属性:debug、managedResource、port和shutdown,这些属性由嵌套在mbean元素内部的四个attribute元素描述。该MBean还公开了一个名为store的方法,该方法由operation元素描述。
Writing Your Own Model MBean Class(编写自己的模型 MBean 类)
When using Commons Modeler, you define the type of your model MBean in the className attribute of your mbean element. By default, Commons Modeler uses the org.apache.commons.modeler.BaseModelMBean class. However, there are circumstances where you want to extend BaseModelMBean:
在使用Commons Modeler时,您需要在mbean元素的className属性中定义您的模型MBean的类型。默认情况下,Commons Modeler使用org.apache.commons.modeler.BaseModelMBean类。然而,在某些情况下,您可能希望扩展BaseModelMBean:
- You want to override the property or method of the managed resource.
- You want to add an attribute or operation that is not defined in the managed resource
- 您想要覆盖受管资源的属性或方法。
- 您想要添加一个在受管资源中未定义的属性或操作。
Catalina provides many subclasses of BaseModelMBean in the org.apache.catalina.mbeans package, and you'll learn about them shortly
Catalina在org.apache.catalina.mbeans包中提供了许多BaseModelMBean的子类,您很快就会了解它们。
Registry(登记处)
The API centers on the org.apache.commons.modeler.Registry class. Here are some of the things you can do with this class:
API 的核心是 org.apache.commons.modeler.Registry 类。以下是您可以使用此类执行的一些操作:
- Obtain an instance of javax.management.MBeanServer (so you don't need to call the createMBeanServer method of javax.management.MBeanServerFactory).
- Read an mbean descriptor file using the loadRegistry method.
- Create a ManagedBean object that you can use to construct a model MBean.
- 获取javax.management.MBeanServer的实例(这样您就不需要调用javax.management.MBeanServerFactory的createMBeanServer方法)。
- 使用loadRegistry方法读取mbean描述符文件。
创建一个ManagedBean对象,您可以使用它来构造一个模型MBean。
ManagedBean(托管类)
A ManagedBean object describes a model MBean and replaces a javax.management.MBeanInfo object.
ManagedBean 对象描述一个模型 MBean,并取代 javax.management.MBeanInfo 对象。
BaseModelMBean
The org.apache.commons.modeler.BaseModelMBean class implements the javax.management.modelmbean.ModelMBean interface. Using this class, you don't need to use the javax.management.modelmbean.RequiredModelMBean class.
org.apache.commons.modeler.BaseModelMBean 类实现了 javax.management.modelmbean.ModelMBean 接口。
使用该类时,您无需使用 javax.management.modelmbean.RequiredModelMBean 类。
One particularly useful field of this class is the resource field that represents the resource managed by this model MBean. The resource field has the following definition:
该类的一个特别有用的字段是资源字段,它表示由该模型 MBean 管理的资源。
资源字段的定义如下:
protected java.lang.Object resource;
Using the Modeler API(使用建模 API)
The Car class whose object we want to manage is given in Listing 20.7.
我们要管理的汽车类对象见清单 20.7。
Listing 20.7: The Car class
清单 20.7: 汽车类
package ex20.pyrmont.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.");
}
}
With Commons Modeler, you don't hard code the attributes and operations of your managed object. Instead, you list them in an XML document which acts as a descriptor for your model MBean(s). In this example, such a document takes the form of the car-mbean-descriptor.xml given in Listing 20.8.
有了 Commons Modeler,你就不用硬编码托管对象的属性和操作了。
取而代之的是在 XML 文档中列出这些属性和操作,作为模型 MBean 的描述符。
在本例中,这种文档的形式是清单 20.8 中的 car-mbean-descriptor.xml。
Listing 20.8: The car-mbean-descriptor.xml file、
清单 20.8:car-mbean-descriptor.xml 文件
Now, you need the agent class (ModelAgent.java) in Listing 20.9.
现在,您需要清单 20.9 中的代理类 (ModelAgent.java)。
Listing 20.9: The ModelAgent Class
清单 20.9: ModelAgent 类
package ex20.pyrmont.modelmbeantest2;
import java.io.InputStream;
import java.net.URL;
import javax.management.Attribute;
import javax.management.MalformedObjectNameException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import org.apache.commons.modeler.ManagedBean;
import org.apache.commons.modeler.Registry;
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
("/ex20/pyrmont/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();
MBeanServer mBeanServer = agent.getMBeanServer();
Car car = new Car();
System.out.println("Creating ObjectName");
ObjectName objectName = agent.createObjectName();
try {
ModelMBean modelMBean = agent.createModelMBean("myMBean");
modelMBean.setManagedResource(car, "ObjectReference");
mBeanServer.registerMBean(modelMBean, objectName);
}
catch (Exception e) {
System.out.println(e.toString());
}
// 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);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
See how the agent class is much shorter when using Commons Modeler?
看到使用 Commons Modeler 时,代理类是如何缩短的吗?
Catalina's MBeans(Catalina的MBeans)
As mentioned at the beginning of this chapter, Catalina provides a number of MBean classes in the org.apache.catalina.mbeans package. All these MBeans extend the org.apache.commons.modeler.BaseModelMBean class either directly or indirectly. This section discusses the three most important MBean classes that Tomcat 4 provides: ClassNameMBean, StandardServerMBean, and MBeanFactory. You should find no problem understanding other model MBean classes in Catalina if you can understand these three classes. The three classes are discussed in this section. In addition, the MBeanUtil class in the org.apache.catalina.mbeans package is also explained.
如本章开头所提到的,Catalina在org.apache.catalina.mbeans包中提供了一些MBean类。所有这些MBean类直接或间接地继承自org.apache.commons.modeler.BaseModelMBean类。本节讨论了Tomcat 4提供的三个最重要的MBean类:ClassNameMBean、StandardServerMBean和MBeanFactory。如果你能理解这三个类,那么你应该没有问题理解Catalina中的其他模型MBean类。本节将讨论这三个类。此外,org.apache.catalina.mbeans包中的MBeanUtil类也会进行解释。
ClassNameMBean
The org.apache.catalina.mbeans.ClassNameMBean class extends org.apache.commons.modeler.BaseModelMBean. It provides the write-only property className that represents the class name of the managed resource. The ClassNameMBean class is given in Listing 20.10.
org.apache.catalina.mbeans.ClassNameMBean类继承自org.apache.commons.modeler.BaseModelMBean类。它提供了只写属性className,表示受控资源的类名。ClassNameMBean类在代码清单20.10中给出。
Listing 20.10: The ClassNameMBean class
清单 20.10:ClassNameMBean 类
package org.apache.catalina.mbeans;
import javax.management.MBeanException;
import javax.management.RuntimeOperationsException;
import org.apache.commons.modeler.BaseModelMBean;
public class ClassNameMBean extends BaseModelMBean {
public ClassNameMBean()
throws MBeanException, RuntimeOperationsException {
super();
}
public String getClassName() {
return (this.resource.getClass().getName());
}
}
The ClassNameMBean class is an example of a subclass of BaseModelMBean that was written to provide a property that is not available in the managed resource itself. Many mbean elements defined in the mbeans-descriptors.xml file use this class as their type of Model MBean.
ClassNameMBean 类是 BaseModelMBean 子类的一个示例,编写它的目的是为了提供托管资源本身所不具备的属性。
在 mbeans-descriptors.xml 文件中定义的许多 mbean 元素都使用该类作为其模型 MBean 类型。
StandardServerMBean
The StandardServerMBean class extends org.apache.commons.modeler.BaseModelMBean to manage an instance of org.apache.catalina.core.StandardServer. The StandardServerMBean class (given in Listing 20.11) is an example of a model MBean class that is written to override a method (i.e. the store method) in the managed resource. When the store method is invoked by a management application, the store method in the StandardServerMBean (and not that in the managed StandardServer object) that gets executed.
StandardServerMBean 类扩展了 org.apache.commons.modeler.BaseModelMBean,用于管理 org.apache.catalina.core.StandardServer 的实例。
StandardServerMBean 类(在清单 20.11 中给出)是模型 MBean 类的一个示例,该类的编写目的是覆盖受管资源中的一个方法(即存储方法)。
当管理应用程序调用存储方法时,将执行 StandardServerMBean 中的存储方法(而不是受管 StandardServer 对象中的存储方法)。
Listing 20.11: The StandardServerMBean class
清单 20.11:StandardServerMBean 类
package org.apache.catalina.mbeans;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.RuntimeOperationsException;
import org.apache.catalina.Server;
import org.apache.catalina.ServerFactory;
import org.apache.catalina.core.StandardServer;
import org.apache.commons.modeler.BaseModelMBean;
public class StandardServerMBean extends BaseModelMBean {
private static MBeanServer mserver = MBeanUtils.createServer();
public StandardServerMBean()
throws MBeanException, RuntimeOperationsException {
super();
}
public synchronized void stored 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");
}
}
}
}
The StandardServerMBean class is an example of a model MBean class that subclasses BaseModelMBean to override a method in the managed resource.
StandardServerMBean类是一个模型MBean类的示例,它继承了BaseModelMBean类,以重写托管资源中的一个方法。
MBeanFactory
The MBeanFactory class represents a factory object that creates all model MBeans that manage various resources in Catalina. The MBeanFactory class also provides methods for deleting these MBeans.
MBeanFactory类表示一个工厂对象,它创建了Catalina中管理各种资源的所有模型MBeans。MBeanFactory类还提供了删除这些MBeans的方法。
As an example, take a look at the createStandardContext method in Listing 20.12.
以createStandardContext方法为例,请参考第20.12节的代码。
Listing 20.12: The createStandardContext method
第20.12节:createStandardContext方法
public String createStandardContext(String parent,
String path, String docBase) throws Exception {
// Create a new StandardContext instance
StandardContext context = new StandardContext();
path = getPathStr(path);
context.setPath(path);
context.setDocBase(docBase);
ContextConfig contextConfig = new ContextConfig();
context.addLifecycleListener(contextConfig);
// Add the new instance to its parent component
ObjectName pname = new ObjectName(parent);
Server server = ServerFactory.getServer();
Service service =
server.findService(pname.getKeyProperty("service"));
Engine engine = (Engine) service.getContainer();
Host host = (Host) engine.findChild(pname.getKeyProperty("host"));
// Add context to the host
host.addChild(context);
// Return the corresponding MBean name
ManagedBean managed = registry.findManagedBean("StandardContext");
ObjectName oname =
MBeanUtils.createObjectName(managed.getDomain(), context);
return (oname.toString());
}
MBeanUtil
The org.apache.catalina.mbeans.MBeanUtil class is a utility class that provides static methods for creating various MBeans to manage Catalina objects, static methods for deleting those MBeans, and static methods for creating object names. For example, the createMBean method in Listing 20.13 creates a model MBean for a org.apache.catalina.Server object.
org.apache.catalina.mbeans.MBeanUtil类是一个实用类,提供了静态方法来创建各种MBean以管理Catalina对象,删除这些MBean的静态方法,以及创建对象名称的静态方法。
例如,在清单20.13中的createMBean方法创建了一个用于管理org.apache.catalina.Server对象的模型MBean。
Listing 20.13: The createMBean method that creates a model MBean that manages a Server object.
清单20.13:创建一个管理Server对象的模型MBean的createMBean方法。、
public static ModelMBean createMBean(Server server) throws Exception {
String mname = createManagedName(server);
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(server);
ObjectName oname = createObjectName(domain, server);
mserver.registerMBean(mbean, oname);
return (mbean);
}
Catalina's MBeans Creation(卡塔利娜的 MBeans 创作)
Now that you are familiar with some of the model MBean in Catalina, we will take a look at how these MBeans are created and made available to management applications.
现在您已经熟悉了 Catalina 中的一些模型 MBean,我们将看看这些 MBean 是如何创建并提供给管理应用程序的。
The server.xml file, the configuration file of Tomcat, defines the following Listener element inside the Server element:
Tomcat 的配置文件 server.xml 文件在服务器元素内定义了以下 Listener 元素:
...
This will add a listener of type org.apache.catalina.mbeans.ServerLifecycleListener to the org.apache.catalina.core.StandardServer object that represents a Server. When the StandardServer instance is started, it fires a START_EVENT event, as defined in the start method of the StandardServer class:
这将为表示服务器的 org.apache.catalina.core.StandardServer 对象添加一个 org.apache.catalina.mbeans.ServerLifecycleListener 类型的监听器。
当 StandardServer 实例启动时,它会触发一个 START_EVENT 事件,该事件在 StandardServer 类的 start 方法中定义:
public void start() throws LifecycleException {
...
lifecycle.fireLifecycleEvent(START_EVENT, null);
...
}
When the StandardServer object is stopped, a STOP_EVENT event is triggered, as defined in its stop method:
当 StandardServer 对象停止时,会触发一个 STOP_EVENT 事件,该事件在其 stop 方法中定义:
public void stop() throws LifecycleException {
...
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
...
}
These events will cause the lifecycleEvent method of the ServerLifecycleListener class to be executed. Listing 20.14 presents the lifecycleEvent method.
这些事件将导致执行 ServerLifecycleListener 类的 lifecycleEvent 方法。
清单 20.14 介绍了 lifecycleEvent 方法。
public void lifecycleEvent(LifecycleEvent event) {
Lifecycle lifecycle = event.getLifecycle();
if (Lifecycle.START_EVENT.equals(event.getType())) {
if (lifecycle instanceof Server) {
// Loading additional MBean descriptors
loadMBeanDescriptors();
createMBeans();
}
}
else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
if (lifecycle instanceof Server) {
destroyMBeans();
}
}
else if (Context.RELOAD_EVENT.equals(event.getType())) {
if (lifecycle instanceof StandardContext) {
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());
}
}
}
}
The createMBeans method is the method that creates all the MBeans in
createMBeans 方法是创建 Catalina 中所有 MBeans 的方法。
Catalina. This method starts off by creating an instance of MBeanFactory, a model MBean class explained in the previous section.
中创建所有 MBean 的方法。该方法首先创建 MBeanFactory 的实例,MBeanFactory 是上一节中解释过的 MBean 模型类。
Listing 20.15: The createMBeans method in ServerLifecycleListener
清单 20.15:ServerLifecycleListener 中的 createMBeans 方法
protected void createMBeans() {
try {
MBeanFactory factory = new MBeanFactory();
createMBeans(factory);
createMBeans(serverFactory.getserver());
}
catch (MBeanException t) {
Exception e = t.getTargetException();
if (e == null)
e = t;
log("createMBeans: MBeanException", e);
}
catch (Throwable t) {
log("createMBeans: Throwable", t);
}
}
The first createMBeans method uses the MBeanUtil class to create an ObjectName for the MBeanFactory and register it in the MBean server.
第一个createMBeans方法使用MBeanUtil类为MBeanFactory创建一个ObjectName,并将其注册到MBean服务器中。
The second createMBeans method takes an org.apache.catalina.Server object and creates a model MBean for it. It is interesting to trace this createMBeans method (presented in Listing 20.16).
第二个createMBeans方法接受一个org.apache.catalina.Server对象,并为其创建一个模型MBean。
追踪这个createMBeans方法是很有趣的(见代码清单20.16)。
Listing 20.16: The createMBeans method that creates an MBean for a Server object
代码清单20.16:创建一个Server对象的MBean的createMBeans方法
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]);
}
}
Note that the createMBeans method in Listing 20.16 calls the following line in the for loop that iterates all Service objects in the StandardServer instance:
请注意,清单 20.16 中的 createMBeans 方法在遍历 StandardServer 实例中所有服务对象的 for 循环中调用了下面一行:
createMBeans(services[i]);
This method creates MBean instances for the services and calls the createMBeans method for creating MBean objects for all the connectors and engines in the service The createMBeans method that creates a Service MBean is given in Listing 20.17.
此方法为服务创建MBean实例,并调用createMBeans方法为服务中的所有连接器和引擎创建MBean对象。创建Service MBean的createMBeans方法在列表20.17中给出。
Listing 20.17: The createMBeans method that creates a Service MBean
列表20.17:创建Service MBean的createMBeans方法
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);
}
}
The createMBeans (engine) method, as you might suspect, calls the createMBeans method that creates the MBeans for hosts:
正如你所猜测的那样,createMBeans (engine) 方法会调用 createMBeans 方法,为主机创建 MBeans:
protected void createMBeans(Engine engine) throws Exception {
// Create the MBean for the Engine itself
if (debug >= 2) {
log("Creating MBean for Engine " + engine);
}
MBeanUtils.createMBean(engine);
...
Container hosts[] = engine.findChildren();
for (int j = 0; j < hosts.length; j++) {
createMBeans((Host) hosts[j]);
}
...
}
The createMBeans (host) method in turns creates a ContextMBean, like the following:
createMBeans (host) 方法会创建一个 ContextMBean,如下所示:
protected void createMBeans(Host host) throws Exception {
...
MBeanUtils.createMBean(host);
...
Container contexts[] = host.findChildren();
for (int k = 0; k < contexts.length; k++) {
createMBeans((Context) contexts[k]);
}
...
}
The createMBeans (context) method is as follows:
protected void createMBeans(Context context) throws Exception {
...
MBeanUtils.createMBean(context);
...
context.addContainerListener(this);
if (context instanceof StandardContext) {
((StandardContext) context).addPropertyChangeListener(this);
((StandardContext) context).addLifecycleListener(this);
}
// If the context is privileged, give a reference to it
// in a servlet context attribute if (context.getPrivileged()) {
context.getServletContext().setAttribute
(Globals.MBEAN_REGISTRY_ATTR, MBeanUtils.createRegistry());
context.getServletContext().setAttribute
(Globals.MBEAN_SERVER_ATTR, MBeanUtils.createServer());
}
...
}
If the context's privileged property is true, two attributes will be created and stored in the ServletContext object for the web application. The keys for those attributes are Globals.MBEAN_REGISTRY_ATTR and Globals.MBEAN_SERVER_ATTR. Here is a fragment from the org.apache.catalina.Globals class:
如果上下文的特权属性为true,则会在Web应用程序的ServletContext对象中创建并存储两个属性。这些属性的键是Globals.MBEAN_REGISTRY_ATTR和Globals.MBEAN_SERVER_ATTR。
下面是来自org.apache.catalina.Globals类的一个片段:
/**
* The servlet context attribute under which the managed bean Registry
* will be stored for privileged contexts (if enabled).
*/
public static final String MBEAN_REGISTRY_ATTR =
"org.apache.catalina.Registry";
/**
* The servlet context attribute under which the MBeanServer will be
* stored for privileged contexts (if enabled).
*/
public static final String MBEAN_SERVER_ATTR =
"org.apache.catalina.MBeanServer";
The MBeanUtils.createRegistry method returns a Registry instance. The MBeanUtils.createServer method returns an instance of javax.management.MBeanServer instance with which all Catalina's MBeans are registered.
MBeanUtils.createRegistry 方法返回一个注册表实例。
MBeanUtils.createServer 方法返回一个 javax.management.MBeanServer 实例,所有 Catalina 的 MBeans 都在该实例中注册。
In other words, you can obtain these Registry and MBeanServer objects from a web application whose privileged property is set to true. The next section discusses how you can create a JMX manager application to manage Tomcat.
换句话说,您可以从特权属性设置为 true 的网络应用程序中获取这些注册表和 MBeanServer 对象。
下一节将讨论如何创建一个 JMX 管理器应用程序来管理 Tomcat。
The Application(应用)
The application here is a web application for administering Tomcat. It is simple but enough to give you a general idea of how to use the MBeans exposed by Catalina. You can use it to list all the ObjectName instances in Catalina, as well as list all the contexts currently running and remove any of them.
这里的应用程序是一个用于管理 Tomcat 的网络应用程序。
它很简单,但足以让您大致了解如何使用 Catalina 公开的 MBeans。
您可以用它来列出 Catalina 中的所有 ObjectName 实例,以及列出当前运行的所有上下文并删除其中任何一个。
First of all, you need to create a descriptor for the application (Listing 20.18). You must place this file in the in %CATALINA_HOME%/webapps directory
Listing 20.18: The myadmin.xml file
One thing you need to worry about is to make sure that the privileged property of the Context element is set to true. The docBase attribute specifies the location of the application.
需要注意的一点是,确保 Context 元素的 privileged 属性设置为 true。docBase 属性指定了应用程序的位置。
The application consists of one servlet, presented in Listing 20.19.
应用程序由一个 servlet 组成,如清单 20.19 所示。
Listing 20.19: The MyAdminServlet class
清单 20.19:MyAdminServlet 类
package myadmin;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Set;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.modeler.Registry;
public class MyAdminServlet extends HttpServlet {
private Registry registry;
private MBeanServer mBeanServer;
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;
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if (registry==null || mBeanServer==null) {
out.println("Registry or MBeanServer not found");
return;
}
out.println("");
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 command");
}
out.println("");
}
private void listAllManagedBeans(PrintWriter out) {
String[] managedBeanNames = registry.findManagedBeans();
for (int i=0; i ");
}
}
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 +
" remove
");
}
}
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.println("context removed");
}
catch (Exception e) {
out.print(e.toString());
}
}
}
catch (Exception e) {
}
}
}
Finally, you need the application deployment descriptor in Listing 20.20.
最后,您需要清单 20.20 中的应用程序部署描述符。
Listing 20.20: The web.xml file
清单 20.20:web.xml 文件
myAdmin
myadmin.MyAdminServlet
myAdmin
/myAdmin
To list all ObjectName instances, use the following URL:
要列出所有 ObjectName 实例,请使用以下 URL:
http://localhost:8080/myadmin/myAdmin?action=listAllMBeans
You will see a list of MBean objects. Here are the first six of them:
您将看到一个 MBean 对象列表。下面是前六个对象:
MemoryUserDatabase
DigestAuthenticator
BasicAuthenticator
UserDatabaseRealm
SystemErrLogger
Group
内存用户数据库
摘要验证器
基本验证器
用户数据库域
系统错误记录器
组
To list all the contexts, use this URL:
要列出所有上下文,请使用此 URL:
http://localhost:8080/myadmin/myAdmin?action=listAllContexts
You will see all the running applications. To remove any of them, click the remove hyperlink.
您将看到所有正在运行的应用程序。
要删除其中任何一个,请单击删除超链接。
Summary(摘要)
In this chapter you have learned how to manage Tomcat using JMX. You have been introduced to the two of four types of MBeans and developed a simple Admin application to use the MBeans offered by Catalina
在本章中,您将学习如何使用 JMX 管理 Tomcat。
您还了解了四种 MBeans 中的两种,并开发了一个简单的管理应用程序来使用 Catalina 提供的 MBeans