javax.management

接口
异常
注释
@Documented
@Retention(value=RUNTIME)
@Target(value=TYPE)
public @interface MXBean

显式地标记某一接口是否为 MXBean 接口的注释。默认情况下,如果接口的名称以 MXBean 结尾(如 SomethingMXBean),则该接口为 MXBean 接口。以下接口是 MXBean 接口:

    public interface WhatsitMXBean {}

    @MXBean
    public interface Whatsit1Interface {}

    @MXBean(true)
    public interface Whatsit2Interface {}
    

以下接口不是 MXBean 接口:

    public interface Whatsit3Interface{}

    @MXBean(false)
    public interface MisleadingMXBean {}
    

MXBean 规范

MXBean 概念提供了一种对 MBean 进行编码的简单方式,这种方式只引用一组预定义的类型,这些类型由 javax.management.openmbean 定义。使用这种方式可以确保任何客户端(包括远程客户端)都可以使用您的 MBean,无需客户端具有访问表示 MBean 类型的特定于模型的类 的权限。

与 Standard MBean 概念相比,这些概念更容易理解一些。以下是将管理对象表示为 Standard MBean 和 MXBean 的方式:

Standard MBean MXBean
public interface MemoryPoolMBean {
String getName();
MemoryUsage getUsage();
    // ...
}
          
public interface MemoryPoolMXBean {
String getName();
MemoryUsage getUsage();
    // ...
}
          

如您所见,这些定义非常相似。唯一的不同是命名接口的约定将使用 MXBean 的 Something MXBean,而不是 Standard MBean 的 Something MBean

在此管理对象中,有一种类型为 MemoryUsage 的称作 Usage 的属性。此类属性的要点是,它给出了一组数据项的统一快照。例如,它可能包括内存池中目前已使用的内存量,以及内存池的当前最大量。如果这些是单独的项(通过单独的 getAttribute 调用获得),那么我们可以在不同时间查看不一致的值。我们可能获得大于 max 值的 used 值。

因此,可以按如下形式定义 MemoryUsage

Standard MBean MXBean
public class MemoryUsage implements Serializable {
// standard JavaBean conventions with getters

public MemoryUsage(long init, long used,
long committed, long max) {...}
long getInit() {...}
long getUsed() {...}
long getCommitted() {...}
long getMax() {...}
}
          
public class MemoryUsage {
// standard JavaBean conventions with getters
@ConstructorProperties({"init", "used", "committed", "max"})
public MemoryUsage(long init, long used,
long committed, long max) {...}
long getInit() {...}
long getUsed() {...}
long getCommitted() {...}
long getMax() {...}
}
          

两种情况下的定义是相同的(使用 MXBean 的情况除外),不再需要将 MemoryUsage 标记为 Serializable(尽管可以这样做)。另一方面,我们添加了一个 @ConstructorProperties 注释,以便将构造方法参数链接到相应的获取方法。下面将看到更多这方面的信息。

MemoryUsage 是一个特定于模型的类。使用 Standard MBean 时,如果 MemoryUsage 类对于 MBean Server 的客户端为未知类,那么该客户端将无法访问 Usage 属性。假定该客户端是一个基于 JMX 技术的通用控制台。那么必须使用该控制台可以连接到的每个应用程序的特定于模型的类来配置此控制台。对于未用 Java 语言编写的客户端,问题甚至更为严重。此时可能无法通知客户端 MemoryUsage 是什么样的。

这就是 MXBean 与 Standard MBean 的不同之处。尽管我们以几乎完全相同的方式定义了管理接口,但 MXBean 框架会从 Java 平台将特定于模型的类转换 为标准类。使用数组以及标准 javax.management.openmbean 包中的 CompositeDataTabularData 类,就有可能只使用标准类来构建任意复杂度的数据结构。

如果比较两种模型的客户端的外观,这将变得更清楚:

Standard MBean MXBean
String name = (String)
mbeanServer.getAttribute(objectName, "Name");
MemoryUsage usage = (MemoryUsage)
mbeanServer.getAttribute(objectName, "Usage");
long used = usage.getUsed();
          
String name = (String)
mbeanServer.getAttribute(objectName, "Name");
CompositeData usage = (CompositeData)
mbeanServer.getAttribute(objectName, "Usage");
long used = (Long) usage.get("used");
          

对于具有简单类型(如 String)的属性,代码是相同的。但对于具有复杂类型的属性,Standard MBean 代码要求客户端知道特定于模型的类 MemoryUsage,而 MXBean 代码则不需要任何非标准类。

此处显示的客户端代码对于 MXBean 客户端而言更加复杂。但是,如果客户端确实知道该模型、此处的接口 MemoryPoolMXBeanMemoryUsage 类,则该客户端可以构造一个代理。在预先知道模型的情况下,建议您使用这种方式与管理对象进行交互,不必考虑正在使用的是 Standard MBean 还是 MXBean:

Standard MBean MXBean
MemoryPoolMBean proxy =
JMX.newMBeanProxy(
mbeanServer,
objectName,
MemoryPoolMBean.class);
String name = proxy.getName();
MemoryUsage usage = proxy.getUsage();
long used = usage.getUsed();
          
MemoryPoolMXBean proxy =
JMX.newMXBeanProxy(
mbeanServer,
objectName,
MemoryPoolMXBean.class);
String name = proxy.getName();
MemoryUsage usage = proxy.getUsage();
long used = usage.getUsed();
          

对于 Standard MBean 和 MXBean 而言,实现 MemoryPool 对象的方式是类似的。

Standard MBean MXBean
public class MemoryPool
implements MemoryPoolMBean {
public String getName() {...}
public MemoryUsage getUsage() {...}
    // ...
}
          
public class MemoryPool
implements MemoryPoolMXBean {
public String getName() {...}
public MemoryUsage getUsage() {...}
    // ...
}
          

在两种情况下,在 MBean Server 中注册 MBean 的方式是相同的:

Standard MBean MXBean
{
MemoryPoolMBean pool = new MemoryPool();
mbeanServer.registerMBean(pool, objectName);
}
          
{
MemoryPoolMXBean pool = new MemoryPool();
mbeanServer.registerMBean(pool, objectName);
}
          

MXBean 的定义

MXBean 是一种 MBean。MXBean 对象可以直接在 MBean Server 中注册,也可以用作在 MBean Server 中注册的 StandardMBean 和结果 MBean 的参数。

当使用 MBeanServer 接口的 registerMBeancreateMBean 方法在 MBean Server 中注册某个对象时,要检查该对象的类来确定 MBean 的类型:

  • 如果该类实现了接口 DynamicMBean,则 MBean 是一个 Dynamic MBean。注意,因为 StandardMBean 类实现了此接口,所以这种情况可应用于使用 StandardMBean 类创建的 Standard MBean 或 MXBean。
  • 否则,如果该类与 Standard MBean 命名约定匹配,则 MBean 是一个 Standard MBean。
  • 否则它可能是一个 MXBean。检查由对象实现的那组接口,以获得具有以下特性的接口:
    • 具有一个类名称 SMXBean(其中的 S 为非空字符串),且没有注释 @MXBean(false)
    • 具有注释 @MXBean(true) 或只有 @MXBean
    如果确实有这样一个接口,或者如果有一个作为其他所有接口的子接口的接口,则该对象是一个 MXBean。相关接口是 MXBean 接口。在上述示例中,MXBean 接口是 MemoryPoolMXBean
  • 如果这些条件都不满足,则 MBean 无效,并且试图对其进行注册将生成 NotCompliantMBeanException

作为参数出现的每个 Java 类型或 MXBean 接口中某一方法的返回类型在使用下面的规则进行转换时,必须是可转换的。此外,参数必须是可重新构造的,正如下面所定义的那样。

尝试构造不符合上述规则的 MXBean 将产生一个异常。

命名约定

与在 Standard MBean 中一样,相同的命名约定可应用于 MXBean 中的各种方法:

  1. 方法 T getN() 明确说明存在一个名为 N 的可读属性,该方法中的 T 是一种 Java 类型(不可以为 void),N 为非空字符串。该属性的 Java 类型和 Open 类型是根据下面的映射规则确定的。在查找获取方法时,将忽略从 Object 继承的方法 final Class getClass()
  2. 方法 boolean isN() 明确说明存在一个名为 N 的可读属性,且该属性的 Java 类型为 boolean,Open 类型为 SimpleType.Boolean
  3. 方法 void setN(T x) 明确说明存在一个名为 N 的可写属性。该属性的 Java 类型和 Open 类型是根据下面的映射规则确定的。(当然,参数的名称 x 无关紧要。)
  4. 其他每个方法都明确说明存在一个名称与该方法相同的操作。返回值和每个参数的 Java 类型和 Open 类型是根据下面的映射规则确定的。

getNisN 的规则共同定义了 getter 的概念。setN 的规则定义了 setter 的概念。

两个获取方法具有相同名称或者两个设置方法具有相同名称是一种错误。如果一个获取方法和一个设置方法具有相同的名称,则二者的类型 T 必须相同。在这种情况下,属性为 read/write。如果只有一个获取方法或只有一个设置方法,则属性分别为 read-only 或 write-only。

类型映射规则

MXBean 是一种 Open MBean,由 javax.management.openmbean 包定义。这意味着属性类型、操作参数和操作返回值都必须是可以使用 Open Types(即 OpenType 的四个标准子类)描述的。MXBean 通过将 Java 类型映射为 Open Types 来实现此操作。

对于每个 Java 类型 J,MXBean 映射关系根据以下信息来描述:

  • 相应的 Open Type,即 opentype(J)。这是 OpenType 的子类的一个实例。
  • 映射的 Java 类型(opendata(J))对于任何给定的 opentype(J) 都是相同的。这是一个 Java 类。
  • 将值从类型 J 转换为类型 opendata(J) 的方式。
  • 将值从类型 opendata(J) 转换为类型 J 的方式(如果可以转换)。

例如,对于 Java 类型 List<String>

如果没有用来从 J 中派生 opentype(J) 的映射规则,则 J 不能是 MXBean 接口中方法参数或返回值的类型。

如果有办法将 opendata(J) 转换回 J,则我们说 J可重新构造的。MXBean 接口中的所有方法参数必须是可重新构造的,这是因为当 MXBean 框架调用某一方法时,它需要将这些参数从 opendata(J) 转换为 J。在由 JMX.newMXBeanProxy 生成的代理中,MXBean 接口中方法的返回值必须是可重新构造的。

所有 Java 类型和 Open Types 都允许使用 null 值,不可能使用 null 值的一些基本 Java 类型除外。当从类型 J 转换为类型 opendata(J) 或从类型 opendata(J) 转换为类型 J 时,null 值被映射为一个 null 值。

下表总结了类型映射规则。

Java 类型 J opentype(J) opendata(J)
intboolean
(8 个基本 Java 类型)
SimpleType.INTEGER
SimpleType.BOOLEAN
IntegerBoolean
(相应的 boxed 类型)
IntegerObjectName
SimpleType 包含的类型)
相应的 SimpleType J,相同类型
int[]
(具有
基本元素类型的一维数组)
ArrayType.getPrimitiveArrayType(int[].class) J,相同类型
E[]
(具有非基本元素类型 E 的数组;这包括 int[][],其中 Eint[]
ArrayType.getArrayType(opentype(E)) opendata(E)[]
List&lt;E&gt;
Set&lt;E&gt;
SortedSet&lt;E&gt;(参见以下内容)
E[] 相同 E[] 相同
枚举 E
(在 Java 中被声明为 enum E {...}
SimpleType.STRING String
Map&lt;K,V&gt;
SortedMap&lt;K,V&gt;
TabularType
(参见以下内容)
TabularData
(参见以下内容)
MXBean 接口 SimpleType.OBJECTNAME
(参见以下内容)
ObjectName
(参见以下内容)
任何其他类型 CompositeType,如果可能
(参见以下内容)
CompositeData

以下几节将详细解释这些规则。

基本类型的映射

8 种基本 Java 类型(booleanbyteshortintlongfloatdoublechar)都可映射到 java.lang 中的相应 boxed 类型,即 BooleanByte 等。Open Type 是相应的 SimpleType。因此,opentype(long)SimpleType.LONGopendata(long)java.lang.Long

诸如 long[] 之类的基本类型的数组可以直接表示为一种 Open Type。因此,openType(long[])ArrayType.getPrimitiveArrayType(long[].class)opendata(long[])long[]

实际上,普通 intInteger 等之间的差异不会显现出来,因为 JMX API 中的操作总是在 Java 对象上进行,而不是在基本类型上进行。但是,数组中确实 存在这种差异。

集合的映射(List&lt;E&gt; 等)

List&lt;E&gt;Set&lt;E&gt;(如 List<String>Set<ObjectName>)以相同方式映射为相同元素类型的数组,如 String[]ObjectName[]

也可以用相同方式将 SortedSet&lt;E&gt; 映射为 E[],但是只有在 E 是实现 Comparable 的类或接口时,它才是可转换的。因此,SortedSet<String>SortedSet<Integer> 是可转换的,但 SortedSet<int[]>SortedSet<List<String>&gt; 是不可转换的。如果 SortedSet 实例包含一个非 null comparator(),那么对该实例的转换将失败,并抛出 IllegalArgumentException

List&lt;E&gt; 被重新构造为一个 java.util.ArrayList&lt;E&gt;Set&lt;E&gt; 被重新构造为一个 java.util.HashSet&lt;E&gt;SortedSet&lt;E&gt; 被重新构造为一个 java.util.TreeSet&lt;E&gt;

映射的映射关系(Map&lt;K,V&gt; 等)

Map&lt;K,V&gt;SortedMap&lt;K,V&gt;(如 Map<String,ObjectName>)包含 Open Type TabularType,并且可映射为一个 TabularDataTabularType 有两个称为 keyvalue 的项。key 的 Open Type 为 opentype(K)value 的 Open Type 为 opentype(V)TabularType 的索引是单个项 key

例如,用于 Map<String,ObjectName>TabularType 可以使用如下代码构造:

String typeName =
"java.util.Map<java.lang.String, javax.management.ObjectName>";
String[] keyValue =
new String[] {"key", "value"};
OpenType[] openTypes =
new OpenType[] {SimpleType.STRING, SimpleType.OBJECTNAME};
CompositeType rowType =
new CompositeType(typeName, typeName, keyValue, keyValue, openTypes);
TabularType tabularType =
new TabularType(typeName, typeName, rowType, new String[] {"key"});
    

此处的 typeName 由下面将详细介绍的类型名称规则确定。

SortedMap&lt;K,V&gt; 以相同的方式映射,但只有在 K 是实现 Comparable 的类或接口时才是可转换的。因此,SortedMap<String,int[]> 是可转换的,但 SortedMap<int[],String> 是不可转换的。如果 SortedMap 实例包含一个非 null comparator(),那么该实例的转换将失败,并将抛出 IllegalArgumentException

Map&lt;K,V&gt; 被重新构造为一个 java.util.HashMap&lt;K,V&gt;SortedMap&lt;K,V&gt; 被重新构造为一个 java.util.TreeMap&lt;K,V&gt;

TabularData 是一个接口。用于将 Map&lt;K,V&gt; 表示为 Open Data 的具体类是 TabularDataSupport,或是实现作为 TabularDataSupport 序列化的 TabularData 的另一个类。

MXBean 接口的映射

MXBean 接口(或 MXBean 接口中引用的类型)可以引用另一个 MXBean 接口 J。这时 opentype(J)SimpleType.OBJECTNAMEopendata(J)ObjectName

例如,假设您有两个如下所示的 MXBean 接口:

public interface ProductMXBean {
public ModuleMXBean[] getModules();
}

public interface ModuleMXBean {
public ProductMXBean getProduct();
}
    

实现 ModuleMXBean 接口的对象从其 getProduct 方法返回一个实现 ProductMXBean 接口的对象。ModuleMXBean 对象和返回的 ProductMXBean 对象都必须注册为相同 MBean Server 中的 MXBean。

方法 ModuleMXBean.getProduct() 定义了一个称为 Product 的属性。此属性的 Open Type 为 SimpleType.OBJECTNAME,并且相应的 ObjectName 值将是所引用的 ProductMXBean 在 MBean Server 中注册的名称。

如果为 ModuleMXBean 构造一个 MXBean 代理,并调用其 getProduct() 方法,则该代理将通过构造另一个 MXBean 代理将 ObjectName 映射回 ProductMXBean。更正式地说,当使用 JMX.newMXBeanProxy(mbeanServerConnection, objectNameX, interfaceX) 构造一个代理需要将 objectNameY 映射回 interfaceY(另一个 MXBean 接口)时,可以使用 JMX.newMXBeanProxy(mbeanServerConnection, objectNameY, interfaceY) 来完成此操作。该实现可以返回一个以前通过使用相同参数调用 JMX.newMXBeanProxy 创建的代理,或创建一个新代理。

通过对 ModuleMXBean 接口进行以下更改来解释反向映射:

public interface ModuleMXBean {
public ProductMXBean getProduct();
public void setProduct(ProductMXBean c);
}
    

setProduct 方法的存在现在意味着 Product 属性为 read/write。与以前一样,该属性的值是一个 ObjectName。设置属性时,必须将 ObjectName 转换成 setProduct 方法所需要的 ProductMXBean 对象。此对象将是相同 MBean Server 中给定 ObjectName 的 MXBean 代理。

如果为 ModuleMXBean 构造一个 MXBean 代理并调用其 setProduct 方法,则该代理会将其 ProductMXBean 参数映射回 ObjectName。只有在该参数实际上是另一代理时,才能如此操作,这也可用于相同 MBeanServerConnection 中的 ProductMXBean。可以从另一代理(如返回 ProductMXBean 的代理的 ModuleMXBean.getProduct())返回代理;或由 JMX.newMXBeanProxy 创建代理;或使用带有调用处理程序的 Proxy 创建,该调用处理程序是 MBeanServerInvocationHandler 或一个子类。

如果相同的 MXBean 在两个不同的 ObjectName 下注册,那么对哪个 MXBean 进行引用将是不明确的。因此,如果某个 MXBean 对象已经在 MBean Server 中注册并且尝试在相同 MBean Server 的另一名称下对其进行注册,结果将是抛出 InstanceAlreadyExistsException。通常不鼓励在多个名称下注册同一 MBean 对象,因为它显然不适合那些是 NotificationBroadcaster 的 MBean。

其他类型的映射

如果给定的 Java 类或接口 J 与上述表中的其他规则不匹配,则 MXBean 框架会尝试按照以下方式将其映射到 CompositeType。此 CompositeType 的类型名称是根据以下类型名称规则确定的。

使用上述约定检查获取方法的类。(Getter 必须是公共实例方法。)如果没有获取方法,或任何获取方法都有一个不可转换的类型,则 J 是不可转换的。

如果至少有一个获取方法并且每个获取方法都有一个可转换的类型,则 opentype(J) 是一个 CompositeType,它对于每个获取方法都有一个项。如果获取方法为

T getName()
CompositeType 中的项被称为 name,且类型为 opentype(T)。例如,如果该项为
String getOwner()
则该项被称为 owner,且 Open Type 为 SimpleType.STRING。如果该获取方法为
boolean isName()
CompositeType 中的项被称为 name,且类型为 SimpleType.BOOLEAN

注意,第一个字符(或代码点)要转换为小写。这遵守 Java Bean 约定,由于历史原因,该约定与 Standard MBean 约定不同。在 Standard MBean 或 MXBean 接口中,方法 getOwner 定义了名为 Owner 的属性,而在 Java Bean 或映射的 CompositeType 中,方法 getOwner 定义了名为 owner 的属性或项。

如果两个方法生成了相同的项名称(如 getOwnerisOwner,或 getOwnergetowner),则该类型是不可转换的。

当 Open Type 为 CompositeType 时,相应的映射 Java 类型 (opendata(J)) 是 CompositeData。从 J 的实例到对应于刚描述的 CompositeTypeCompositeData 的映射是按以下方式完成的。首先,如果 J 实现了接口 CompositeDataView,则调用该接口的 toCompositeData 方法来完成转换。否则,通过对每个项调用获取方法并将其转换为相应的 Open Data 类型来构造 CompositeData。因此,如下所示的获取方法

List<String> getNames()

将被映射到名称为 "names" 且 Open Type 为 ArrayType(1, SimpleType.STRING) 的项。对 CompositeData 的转换将调用 getNames(),并将结果 List<String> 转换为项 "names" 的 String[]

CompositeData 是一个接口。用于将类型表示为 Open Data 的具体类是 CompositeDataSupport,或者是实现作为 CompositeDataSupport 序列化的 CompositeData 的另一个类。

CompositeData 重新构造 Java 类型 J 的实例

如果 opendata(J) 是 Java 类型 JCompositeData,则要么从 CompositeData 重新构造 J 的实例,要么 J 是不可重新构造的。如果 CompositeData 中的任何项都是不可重新构造的,则 J 也是不可重新构造的。

对于任何给定的 J,都可参考以下规则来确定如何从 CompositeData 重新构造 J 的实例。列表中的第一个适用规则是将被使用的规则。

  1. 如果 J 拥有方法
    public static J from(CompositeData cd)
    ,则调用该方法来重新构造一个 J 实例。

  2. 否则,如果 J 至少有一个带有 ConstructorProperties 注释的公共构造方法,则将调用这些构造方法之一(不一定总是同一个构造方法)来重新构造一个 J 实例。每个这样的注释都必须列出与构造方法的参数数量相同的字符串;每个字符串必须命名一个对应于 J 的获取方法的属性;此获取方法的类型必须与对应构造方法参数的类型相同。如果存在 ConstructorProperties 注释中未提到的获取方法(这些获取方法可能对应于重新构造对象所不需要的信息),这不算是一种错误。

    通过使用 CompositeData 中经过适当重新构造的项来调用构造方法,可以重新构造一个 J 实例。要调用的构造方法将在运行的时候根据实际出现在 CompositeData 中的项来确定,在这种情况下,此 CompositeData 可能来自 J 的较早版本,该版本中没有包含所有的项。如果在构造方法的 ConstructorProperties 注释中命名的所有属性都作为项出现在 CompositeData 中,则该构造方法是适用的。如果没有构造方法是适用的,则尝试重新构造 J 将失败。

    对于任何可能的属性组合,必须是以下情况:(a) 没有适用的构造方法,或 (b) 恰恰有一个适用的构造方法,或 (c) 适用的构造方法之一命名了由其他每个适用构造方法命名的属性的适当超集。(换句话说,在选择构造方法时永远不应该有混淆现象。)如果此条件不为 true,则 J 是不可重新构造的。

  3. 否则,如果 J 具有不带参数的公共构造方法,并且对于类型为 T 且名称为 NJ 中的每个获取方法,都有一个具有相同名称和类型的相应设置方法,则 J 的实例是使用不带参数的构造方法构造的 ,并使用 CompositeData 中经过重新构造的项来调用这些设置方法,以恢复某些值。例如,如果具有方法
    public List<String> getNames()
    ,则还必须有一个应用此规则的方法
    public void setNames(List<String> names)

    如果 CompositeData 来自 J 的较早版本,则有些项可能不会出现。在这种情况下,不会调用相应的设置方法。

  4. 否则,如果 J 是一个除了获取方法之外没有其他方法的接口,则使用具有 CompositeDataInvocationHandler(受正在转换的 CompositeData 支持)的 Proxy 来构造一个 J 实例。

  5. 否则,J 是不可重新构造的。

下面的示例显示了对那些由 intString 组成的类型 NamedNumber 进行编码的不同方式。CompositeType 在各种情况下的形式如下:

CompositeType(
"NamedNumber",                        // typeName
"NamedNumber",                        // description
new String[] {"number", "name"},    // itemNames
new String[] {"number", "name"},    // itemDescriptions
new OpenType[] {SimpleType.INTEGER,
SimpleType.STRING}  // itemTypes
);
      
  1. 静态 from 方法:
    public class NamedNumber {
    public int getNumber() {return number;}
    public String getName() {return name;}
    private NamedNumber(int number, String name) {
    this.number = number;
    this.name = name;
        }
    public static NamedNumber from(CompositeData cd) {
    return new NamedNumber((Integer) cd.get("number"),
    (String) cd.get("name"));
        }
    private final int number;
    private final String name;
    }
              
  2. 带有 @ConstructorProperties 注释的公共构造方法:
    public class NamedNumber {
    public int getNumber() {return number;}
    public String getName() {return name;}
    @ConstructorProperties({"number", "name"})
    public NamedNumber(int number, String name) {
    this.number = number;
    this.name = name;
        }
    private final int number;
    private final String name;
    }
              
  3. 针对每个获取方法的设置方法:
    public class NamedNumber {
    public int getNumber() {return number;}
    public void setNumber(int number) {this.number = number;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public NamedNumber() {}
    private int number;
    private String name;
    }
              
  4. 只带有获取方法的接口:
    public interface NamedNumber {
    public int getNumber();
    public String getName();
    }
              

通常,它更适合只将数据集合表示为不可变 的类。不可变类的实例在被构造之后无法进行更改。注意,CompositeData 本身是不可变的。不可变性有许多优点,最为明显的是线程安全和安全性。因此,如有可能,通常应该采用避免使用设置方法的方式。

递归类型

递归(自引用)类型不能在 MXBean 接口中使用。这是 CompositeType 的不变性导致的。例如,以下类型不能是属性的类型,因为属性引用了自身:

public interface Node {
    public String getName();
    public int getPriority();
    public Node getNext();
}

总是可以像这样重写递归接口,使之不再递归。重写可能需要引入新类型。例如:

public interface NodeList {
    public List<Node> getNodes();
}

public interface Node {
    public String getName();
    public int getPriority();
}

MXBean 的 MBeanInfo 内容

MXBean 是 Open MBean 的一种类型。但是,出于兼容性考虑,其 MBeanInfo 不是一个 OpenMBeanInfo。需要特别指出的是,如果属性、参数或操作返回值的类型是 int 之类的基本类型,或者是 void(针对返回类型),则属性、参数或操作将被分别表示为其 getType()getReturnType() 返回基本名称("int" 等)的 MBeanAttributeInfoMBeanParameterInfoMBeanOperationInfo。即使上面的映射规则指定 opendata 映射是包装类型(Integer 等),情况也是这样。

由直接在 MBean Server 中注册的 MXBean 的 MBeanInfo.getConstructors() 返回的公共构造方法数组,将包含该 MXBean 的所有公共构造方法。如果 MXBean 的类不是公共类,则其构造方法也被视为非公共构造方法。MXBean 的返回列表是使用 StandardMBean 类构造的,其派生方式与 Standard MBean 的相同。不管 MXBean 是如何构造的,其构造方法参数都不服从 MXBean 映射规则,且没有对应的 OpenType

如果直接在 MBean Server 中注册的 MXBean 没有实现 NotificationBroadcaster 接口,则由其 MBeanInfo.getNotifications() 返回的通知类型的数组将为空。否则,它将是在注册 MXBean 时调用 NotificationBroadcaster.getNotificationInfo() 的结果。即使此方法的结果以后发生更改,MBeanInfo.getNotifications() 的结果也不会发生更改。MXBean 的返回列表是使用 StandardMBeanStandardEmitterMBean 类构造的,其派生方式与 Standard MBean 的相同。

MBeanInfo 中包含的所有 MBeanAttributeInfoMBeanParameterInfoMBeanOperationInfo 对象的 Descriptor 都将包含一个字段 openType,其值为由上述映射规则指定的 OpenType。因此,即使在 getType() 为 "int" 时,getDescriptor().getField(&quot;openType&quot;) 仍将是 SimpleType.INTEGER

每个对象的 Descriptor 还有一个 originalType 字段,该字段是一个表示 MXBean 接口中出现的 Java 类型的字符串。此字符串的格式将在下面的类型名称一节中描述。

MBeanInfoDescriptor 将包含一个 mxbean 字段,该字段值是字符串 "true"。

类型名称

有时必须将 MXBean 中方法参数或返回值的未映射类型 T 表示为一个字符串。如果 T 是非一般类型,则此字符串是由 Class.getName() 返回的值。否则,它是 genericstring(T) 的值,定义方式如下:

  • 如果 T 为特殊的非数组类型,则 genericstring(T) 是由 Class.getName() 返回的值,如 &quot;int&quot;&quot;java.lang.String&quot;
  • 如果 T 是数组 E[],则 genericstring(T) 是后跟 &quot;[]&quot;genericstring(E)。例如,genericstring(int[])&quot;int[]&quot;,而 genericstring(List<String>[][])&quot;java.util.List<java.lang.String>[][]&quot;
  • 否则,T 是一个参数化类型(如 List<String>)并且 genericstring(T) 由以下内容组成:由 Class.getName() 返回的参数化类型的完全限定名称;左尖角括号 (&quot;&lt;&quot;);genericstring(A)(其中 A 是第一个类型参数);如果存在第二个类型参数 B,则是一个后跟 genericstring(B)&quot;, &quot;(即逗号加一个空格);右尖角括号 (&quot;&gt;&quot;)。

注意,如果某一方法返回 int[],则这将由 Class.getName() 返回的字符串 &quot;[I&quot; 表示,但如果某一方法返回 List<int[]>,则这将由字符串 &quot;java.util.List<int[]>&quot; 表示。

异常

Java 类型映射 Open 类型时存在的一个问题是会出现 OpenDataException 信号。这可能发生在分析 MXBean 接口时,例如,如果它引用一个类似于没有获取方法的 java.util.Random 的类型。或者发生在转换实例(将返回值从 MXBean 中的方法或参数转换为 MXBean 代理中的方法)时,例如在 SortedSet 拥有非 null Comparator 的情况下从 SortedSet<String> 转换为 String[] 时。

Open 类型映射 Java 类型时存在的一个问题是会出现 InvalidObjectException 信号。这可能发生在分析 MXBean 接口时,例如,当上下文需要可重新构造的类型时,根据上述规则引用了一个不可重新构造的 类型。或者发生在转换实例(MXBean 中某一方法的参数或 MXBean 代理中某一方法的返回值)时,例如在没有具备该名称的 Enum 常量的情况下将 String 转换为 Enum 时。

根据上下文,OpenDataExceptionInvalidObjectException 可以包装在另一个异常(如 RuntimeMBeanExceptionUndeclaredThrowableException)中。 对于每个抛出的异常,条件 C 将为 true:"eOpenDataExceptionInvalidObjectException(如果合适),或者 Ce.getCause()" 中为 ture。

从以下版本开始:
1.6

可选元素摘要
 boolean value
          如果被注释的接口是一个 MXBean 接口,则为 true。
 

value

public abstract boolean value
如果被注释的接口是一个 MXBean 接口,则为 true。

返回:
如果被注释的接口是一个 MXBean 接口,则返回 true。
默认值:
true