注解 MXBean


@Documented @Retention (RUNTIME ) @Target (TYPE ) public @interface MXBean

用于将接口显式标记为 MXBean 接口或不是 MXBean 接口的注释。默认情况下,如果接口是公共的且其名称以 MXBean 结尾(如 SomethingMXBean ),则该接口是 MXBean 接口。以下接口是 MXBean 接口:

  public interface WhatsitMXBean {}

  @MXBean
  public interface Whatsit1Interface {}

  @MXBean(true)
  public interface Whatsit2Interface {}
  

以下接口不是 MXBean 接口:

  interface NonPublicInterfaceNotMXBean{}

  public interface Whatsit3Interface{}

  @MXBean(false)
  public interface MisleadingMXBean {}
  

MXBean 规范

MXBean 概念提供了一种简单的方法来编写仅引用一组预定义类型(由 javax.management.openmbean 定义的类型)的 MBean。通过这种方式,您可以确保任何客户端(包括远程客户端)都可以使用您的 MBean,而无需客户端访问代表您的 MBean 类型的 model-specific classes

与标准 MBean 概念相比,这些概念更容易理解。以下是托管对象如何表示为标准 MBean 和 MXBean:

标准MBean

public interface MemoryPoolMBean {
  String getName();
  MemoryUsage getUsage();
  // ...
}
     

MXBean

public interface MemoryPoolMXBean {
  String getName();
  MemoryUsage getUsage();
  // ...
}
     

如您所见,定义非常相似。唯一的区别是命名接口的约定是对 MXBeans 使用 SomethingMXBean,而不是对 Standard MBean 使用 SomethingMBean

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

所以,我们可以这样定义MemoryUsage

标准MBean

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

MXBean

public class MemoryUsage {
  // standard JavaBean conventions with getters
  @ConstructorParameters({"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(尽管可以)。另一方面,我们添加了一个 @ConstructorParameters 注释来将构造函数参数链接到相应的 getter。我们将在下面看到更多相关信息。

MemoryUsage 是一个 model-specific class。对于 Standard MBean,MBean Server 的客户端如果不知道类 MemoryUsage 则无法访问 Usage 属性。假设客户端是一个基于 JMX 技术的通用控制台。然后,控制台必须使用它可能连接到的每个应用程序的特定于模型的类进行配置。对于不是用 Java 语言编写的客户端,问题更严重。那么可能没有任何方法可以告诉客户端MemoryUsage 是什么样子的。

这是 MXBeans 与标准 MBean 的不同之处。尽管我们以几乎完全相同的方式定义管理接口,但 MXBean 框架将 converts 特定于模型的类转换为来自 Java 平台的标准类。使用数组和标准 javax.management.openmbean 包中的 CompositeData TabularData 类,可以仅使用标准类构建任意复杂度的数据结构。

如果我们比较两种模型的客户端可能是什么样子,这一点就会变得更清楚:

标准MBean

String name = (String)
  mbeanServer.getAttribute (objectName, "Name");
MemoryUsage usage = (MemoryUsage)
  mbeanServer.getAttribute(objectName, "Usage");
long used = usage.getUsed();
    

MXBean

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 客户端来说稍微复杂一些。但是,如果客户端确实知道模型,这里是接口 MemoryPoolMXBean 和类 MemoryUsage,那么它可以构造一个 proxy。当您事先了解模型时,这是与托管对象交互的推荐方式,无论您使用的是标准 MBean 还是 MXBeans:

标准MBean

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

MXBean

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

实现 MemoryPool 对象对于标准 MBean 和 MXBeans 的工作方式类似。

标准MBean

public class MemoryPool
    implements MemoryPoolMBean {
  public String getName() {...}
  public MemoryUsage getUsage() {...}
  // ...
}
    

MXBean

public class MemoryPool
    implements MemoryPoolMXBean {
  public String getName() {...}
  public MemoryUsage getUsage() {...}
  // ...
}
    

在 MBean Server 中注册 MBean 在这两种情况下的工作方式相同:

标准MBean

{
  MemoryPoolMBean pool = new MemoryPool();
  mbeanServer.registerMBean (pool, objectName);
}
    

MXBean

{
  MemoryPoolMXBean pool = new MemoryPool();
  mbeanServer.registerMBean (pool, objectName);
}
    

MXBean 的定义

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

当使用 MBeanServer 接口的 registerMBeancreateMBean 方法在 MBean Server 中注册对象时,将检查对象的类以确定它是什么类型的 MBean:

  • 如果该类实现接口 DynamicMBean ,则该 MBean 是动态 MBean。请注意,类 StandardMBean 实现了此接口,因此这种情况适用于使用类 StandardMBean 创建的标准 MBean 或 MXBean。
  • 否则,如果该类符合标准 MBean 命名约定,则该 MBean 就是标准 MBean。
  • 否则,它可能是一个 MXBean。检查由对象实现的接口集是否存在以下接口:
    • 有一个类名 SMXBean 其中 S 是任何非空字符串,并且没有注释 @MXBean(false) ;和/或
    • 有注释 @MXBean(true) 或只是 @MXBean
    如果只有一个这样的接口,或者如果有一个这样的接口是所有其他接口的子接口,那么该对象就是一个 MXBean。有问题的接口是 MXBean interface 。在上面的示例中,MXBean 接口是 MemoryPoolMXBean
  • 如果这些条件都不满足,则 MBean 无效,并且尝试注册它会生成 NotCompliantMBeanException

使用以下规则,在 MXBean 接口中作为方法的参数或返回类型出现的每个 Java 类型都必须是 convertible。此外,参数必须是下面定义的 reconstructible

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

命名约定

与标准 MBean 中一样,相同的命名约定适用于 MXBean 中的方法:

  1. 方法 T getN() 指定有一个名为 N 的可读属性,其中 T 是 Java 类型(不是 void ),N 是非空字符串。属性的 Java 类型和 Open 类型由下面的映射规则确定。查找getter时忽略继承自 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 的概念。

有两个同名的 getter 或两个同名的 setter 是错误的。如果有同名的 getter 和 setter,则两者的类型 T 必须相同。在这种情况下,该属性是读/写的。如果只有 getter 或只有 setter,则该属性分别为只读或只写。

类型映射规则

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

对于每个 Java 类型 J,MXBean 映射由以下信息描述:

  • 相应的开放类型,opentype(J)。这是 OpenType 子类的实例。
  • mapped Java 类型 opendata(J) 对于任何给定的 opentype(J) 始终相同。这是一个 Java 类。
  • 值如何从类型 J 转换为类型 opendata(J)
  • 值如何从类型 opendata(J) 转换为类型 J(如果可以)。

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

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

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

所有 Java 类型和开放类型都允许空值,但原始 Java 类型除外,因为它们是不可能的。从类型 J 转换为类型 opendata(J) 或从类型 opendata(J) 转换为类型 J 时,空值映射到空值。

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

类型映射规则
Java 类型J opentype(J) opendata(J)
int , boolean
(8 种原始 Java 类型)
SimpleType.INTEGER ,
SimpleType.BOOLEAN
Integer , Boolean
(相应的盒装类型)
Integer , ObjectName
SimpleType 涵盖的类型)
对应的SimpleType J,同类型
int[]
(原始元素类型的一维数组)
ArrayType.getPrimitiveArrayType(int[].class) J,同类型
E []
(具有非原始元素类型 E 的数组;这包括 int[][] ,其中 Eint[]
ArrayType.getArrayType( opentype(E) ) opendata(E) []
List< E >
Set< E >
SortedSet< E >(见下文)
E [] 相同 E [] 相同
枚举E
(在 Java 中声明为 enum E {...}
SimpleType.STRING String
Map< K ,V >
SortedMap< K ,V >
TabularType
(见下文)
TabularData
(见下文)
Record 类 CompositeType ,如果可能的话
(见下文)
CompositeData
(见下文)
一个 MXBean 接口 SimpleType.OBJECTNAME
(见下文)
ObjectName
(见下文)
任何其他类型 CompositeType ,如果可能的话
(见下文)
CompositeData
(见下文)

以下部分提供了这些规则的更多详细信息。

基本类型的映射

种原始 Java 类型(booleanbyteshortint longfloatdoublechar)映射到 java.lang 对应的盒装类型,即 BooleanByte 等。Open Type 是对应的 SimpleType 。因此,opentype( long )SimpleType.LONGopendata( long ) java.lang.Long

long[] 等原始类型的数组可以直接表示为开放类型。因此,openType( long[] ) ArrayType.getPrimitiveArrayType(long[].class)opendata( long[] ) long[]

在实践中,普通 int Integer 等之间的差异不会显示出来,因为 JMX API 中的操作始终针对 Java 对象,而不是原语。但是,差异does 显示在数组中。

集合映射(List< E > 等)

List< E > Set< E > (例如 List<String> Set<ObjectName> )的映射方式与相同元素类型的数组(例如 String[] ObjectName[] )的映射方式相同。

SortedSet< E > 也以与 E [] 相同的方式映射,但仅当 E 是实现 Comparable 的类或接口时才可转换。因此,SortedSet<String>SortedSet<Integer> 是可转换的,但 SortedSet<int[]>SortedSet<List<String>> 不是。 SortedSet 实例的转换将失败并返回 IllegalArgumentException 如果它有一个非空的 comparator()

A List< E > 被重构为 java.util.ArrayList< E >Set< E > 作为 java.util.HashSet< E >SortedSet< E > 作为 java.util.TreeSet< E >

map的映射(Map< K ,V > 等)

Map< KV > SortedMap< KV > ,例如 Map<String,ObjectName> ,具有开放类型 TabularType 并映射到 TabularData TabularType 有两个项目,分别称为 keyvaluekey的开放类型是opentype(K)value的开放类型是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< K ,V > 以相同方式映射,但只有当 K 是实现 Comparable 的类或接口时才可转换。因此,SortedMap<String,int[]> 是可转换的,但 SortedMap<int[],String> 不是。 SortedMap 实例的转换将失败并返回 IllegalArgumentException 如果它有一个非空的 comparator()

Map< K ,V > 被重构为 java.util.HashMap< K ,V >SortedMap< K ,V > 作为 java.util.TreeMap< K ,V >

TabularData 是一个接口。用于表示 Map< KV > 作为开放数据的具体类是 TabularDataSupport ,或者另一个实现 TabularData 的类,序列化为 TabularDataSupport

记录映射

记录J 可以转换为 CompositeType 当且仅当它的所有 components 都可转换为开放类型。否则,它是不可转换的。没有组件的记录不可转换。

将记录类映射到 CompositeType

其组件都可转换为开放类型的记录本身可转换为 CompositeType 。记录类转换为 CompositeType,如下所示。

  • CompositeType 的类型名称是记录类的名称。
  • 记录获取器是 记录组件 的访问器。
  • 对于类型为 T 的每个记录组件,CompositeType 中的项目与记录组件具有相同的名称,其类型为 opentype(T) ,如上面的 类型映射规则 所定义。

将记录类的实例映射到 CompositeData

从记录类的实例到对应于 CompositeTypeCompositeData 的映射与为 其他类型 指定的相同。

CompositeData 重建记录类的实例

使用其规范构造函数重建记录。规范构造函数不需要存在 @javax.management.ConstructorParameters @java.beans.ConstructorProperties 注释。如果这些注释存在于规范构造函数中,它们将被忽略。

如何从 CompositeData 重建记录类 J 的实例在下面的 CompositeData 重建 Java 类型或记录类 J 的实例 中有详细说明。

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 中注册为 MXBeans。

ModuleMXBean.getProduct() 方法定义了一个名为 Product 的属性。此属性的开放类型是 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 属性是读/写的。和以前一样,此属性的值为 ObjectName 。设置属性后,必须将 ObjectName 转换为 setProduct 方法所需的 ProductMXBean 对象。此对象将是同一 MBean 服务中给定 ObjectName 的 MXBean 代理。

如果您为 ModuleMXBean 创建 MXBean 代理并调用其 setProduct 方法,该代理会将其 ProductMXBean 参数映射回 ObjectName 。这仅在参数实际上是另一个代理时才有效,对于同一个 MBeanServerConnection 中的 ProductMXBean 。代理可以从另一个代理返回(比如 ModuleMXBean.getProduct() 返回 ProductMXBean 的代理);或者它可以由 JMX.newMXBeanProxy 创建;或者它可以使用 Proxy 创建,调用处理程序是 MBeanServerInvocationHandler 或子类。

如果同一个 MXBean 在两个不同的 ObjectName 下注册,则从另一个 MXBean 对该 MXBean 的引用将是不明确的。因此,如果 MXBean 对象已经在 MBean Server 中注册,并且试图以另一个名称在同一 MBean Server 中注册它,则结果为 InstanceAlreadyExistsException 。通常不鼓励使用多个名称注册同一个 MBean 对象,特别是因为它不适用于 NotificationBroadcaster 的 MBean。

其他类型的映射

给定与上表中的其他规则不匹配的 Java 类或接口 J,MXBean 框架将尝试将其映射到 CompositeType ,如下所示。这个CompositeType的类型名称是由下面的类型名称规则决定的。

将 Java 类型 J 映射到 CompositeType

使用约定 多于 检查该类的吸气剂。 (Getter 必须是公共实例方法。)如果没有 getter,或者如果任何 getter 具有不可转换的类型,则 J 不可转换。

如果至少有一个 getter,并且每个 getter 都有一个可转换类型,那么 opentype(J) 是一个 CompositeType,每个 getter 都有一个项目。如果吸气剂是

T getName()
那么 CompositeType 中的项目称为 name 并且类型为 opentype(T) 。例如,如果该项目是
String getOwner()
然后该项目称为 owner 并具有 Open Type SimpleType.STRING 。如果吸气剂是
boolean isName()
那么 CompositeType 中的项目称为 name 并且类型为 SimpleType.BOOLEAN

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

如果两种方法产生相同的项目名称(例如, getOwnerisOwner,或getOwner getowner),则该类型不可转换。

从 Java 类型或记录类实例 J 映射到 CompositeData

当 Open Type 为 CompositeType 时,对应的映射 Java 类型 (opendata(J)) 为 CompositeData 。从 J 实例到对应于刚刚描述的 CompositeTypeCompositeData 的映射如下完成。首先,如果 J 实现了接口 CompositeDataView ,那么调用该接口的 toCompositeData 方法来进行转换。否则,CompositeData 是通过为每个项目调用 getter 并将其转换为相应的开放数据类型来构造的。因此,像这样的吸气剂

List<String> getNames()(或 List<String> names() 记录)

将被映射到名称为“names”且打开类型为 ArrayType(1, SimpleType.STRING) 的项目。转换为 CompositeData 将调用 getNames() 并将生成的 List<String> 转换为项目“names ”的 String[]

CompositeData 是一个接口。用于将类型表示为开放数据的具体类是 CompositeDataSupport ,或者是另一个实现 CompositeData 的类,它序列化为 CompositeDataSupport

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 是一个 Record 类,并且记录规范构造函数适用,则通过调用记录规范构造函数重建 J 的实例。规范构造函数(如果适用)使用来自 CompositeData 的适当重构项进行调用。如果记录组件命名的所有属性都存在于 CompositeData 中,则规范构造函数为 applicable

  3. 否则,如果 J 至少有一个带有 @javax.management.ConstructorParameters @java.beans.ConstructorProperties 注释的公共构造函数,那么将调用其中一个构造函数(不一定总是相同的构造函数)来重建 J 的实例。如果构造函数同时使用 @javax.management.ConstructorParameters@java.beans.ConstructorProperties 进行注释,则将使用 @javax.management.ConstructorParameters 而忽略 @java.beans.ConstructorProperties 。每个这样的注释都必须列出与构造函数具有的参数一样多的字符串;每个字符串必须命名一个与 J 的 getter 对应的属性;并且这个getter的类型必须和对应的构造函数参数的类型相同。 @ConstructorParameters@ConstructorProperties 注释中未提及的吸气剂不是错误(这些可能对应于重建对象不需要的信息)。

    J 的实例是通过使用来自 CompositeData 的适当重构项调用构造函数来重构的。要调用的构造函数将在运行时根据 CompositeData 中实际存在的项目确定,因为这个 CompositeData 可能来自 J 的早期版本,其中并非所有项目都存在。如果在其 @ConstructorParameters@ConstructorProperties 注释中命名的所有属性都作为 CompositeData 中的项存在,则构造函数为 applicable。如果没有适用的构造函数,则重建 J 的尝试将失败。

    对于任何可能的属性组合,必须是 (a) 没有适用的构造函数,或 (b) 只有一个适用的构造函数,或 (c) 其中一个适用的构造函数命名为属性的适当超集由彼此适用的构造函数命名。 (换句话说,在选择哪个构造函数的问题上不应该有歧义。)如果这个条件不成立,那么 J 是不可重构的。

  4. 否则,如果 J 有一个公共的无参数构造函数,并且对于 J 中类型为 T 和名称为 N 的每个 getter 都有一个具有相同名称和类型的相应 setter,则 J 的实例是使用无参数构造函数构造的,并且使用来自 CompositeData 的重建项目调用 setter 以恢复值。例如,如果有一个方法
    public List<String> getNames()
    那么还必须有一个方法
    public void setNames(List<String> names)
    适用此规则。

    如果 CompositeData 来自 J 的早期版本,则某些项目可能不存在。在这种情况下,不会调用相应的设置器。

  5. 否则,如果 J 是一个除了 getter 之外没有其他方法的接口,则 J 的实例是使用 Proxy 和一个 CompositeDataInvocationHandler 由正在转换的 CompositeData 支持的 CompositeDataInvocationHandler 构造的。

  6. 否则,J 不可重构。

java.beans.ConstructorProperties 不可见时(例如,当 java.desktop 模块不可读或运行时映像不包含 java.desktop 模块时),规则 2 不适用。当目标运行时不包含 java.beans 包,并且编译时和运行时环境之间存在不匹配时,J 是使用公共构造函数和 ConstructorProperties 注释编译的,那么 J 是不可重构的,除非另一个规则适用。

以下示例显示了对由 int String 组成的类型 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. 记录:
     public record NamedNumber(int number, String name) {}
         
  3. 带有 @ConstructorParameters 注释的公共构造函数:
    public class NamedNumber {
      public int getNumber() {return number;}
      public String getName() {return name;}
      @ConstructorParameters({"number", "name"})
      public NamedNumber(int number, String name) {
        this.number = number;
        this.name = name;
      }
      private final int number;
      private final String name;
    }
         
  4. 每个吸气剂的二传手:
    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;
    }
         
  5. 只有吸气剂的接口:
    public interface NamedNumber {
      public int getNumber();
      public String getName();
    }
         

对于简单表示数据集合的类来说,最好是 immutable 。不可变类的实例在构造后不能更改。请注意,CompositeData 本身是不可变的。不变性有很多优点,特别是在线程安全和安全性方面。因此,如果可能的话,通常应该避免使用 setter 的方法。

递归类型

递归(自引用)类型不能在 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 。特别是,当属性、参数或操作返回值的类型是原始类型,如 intvoid(对于返回类型)时,属性、参数或操作将分别由 MBeanAttributeInfo 表示, MBeanParameterInfo MBeanOperationInfo getType() getReturnType() 返回原语名称(“int ”等)。即使上面的映射规则指定 opendata 映射是包装类型(Integer 等)也是如此。

MBeanInfo.getConstructors() 为直接在 MBean 服务中注册的 MXBean 返回的公共构造函数数组将包含该 MXBean 的所有公共构造函数。如果 MXBean 的类不是公共的,那么它的构造函数也不会被视为公共的。为使用 StandardMBean 类构造的 MXBean 返回的列表以与标准 MBean 相同的方式派生。无论 MXBean 是如何构建的,其构造函数参数都不受 MXBean 映射规则的约束,并且没有对应的 OpenType

如果 MXBean 未实现 NotificationBroadcaster 接口,则 MBeanInfo.getNotifications() 为直接在 MBean 服务中注册的 MXBean 返回的通知类型数组将为空。否则,它将是注册 MXBean 时调用 NotificationBroadcaster.getNotificationInfo() 的结果。即使此方法的结果随后发生变化,MBeanInfo.getNotifications() 的结果也不会。为使用 StandardMBean StandardEmitterMBean 类构造的 MXBean 返回的列表以与标准 MBean 相同的方式派生。

MBeanInfo 中包含的所有 MBeanAttributeInfoMBeanParameterInfoMBeanOperationInfo 对象的 Descriptor 将具有一个字段 openType,其值是上述映射规则指定的 OpenType 。因此,即使 getType() 为“int”,getDescriptor().getField("openType") 也将为 SimpleType.INTEGER

每个对象的 Descriptor 也将有一个字段 originalType,它是一个字符串,表示出现在 MXBean 接口中的 Java 类型。此字符串的格式在下面的 类型名称 部分中进行了描述。

MBeanInfoDescriptor 将有一个字段 mxbean,其值为字符串“true”。

类型名称

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

  • 如果 T 是非泛型非数组类型,则 genericstring(T)Class.getName() 返回的值,例如 "int" "java.lang.String"
  • 如果 T 是数组 E[] ,则 genericstring(T)genericstring(E) 后跟 "[]" 。例如,genericstring(int[] )"int[]"genericstring( List<String>[][] ) "java.util.List<java.lang.String>[][]"
  • 否则,T 是参数化类型,例如 List<String>genericstring(T) 由以下内容组成:Class.getName() 返回的参数化类型的完全限定名称;左尖括号 ( "<"); genericstring(A) 其中 A 是第一个类型参数;如果有第二个类型参数 B 那么 ", " (一个逗号和一个空格)后跟 genericstring(B) ;一个右尖括号 (">")。

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

异常

映射 from Java 类型 to 开放类型的问题用 OpenDataException 表示。在分析 MXBean 接口时可能会发生这种情况,例如,如果它引用像 java.util.Random 这样没有 getter 的类型。或者在转换实例时(MXBean 中方法的返回值或 MXBean 代理中方法的参数)可能会发生这种情况,例如,如果 SortedSet 具有非空 Comparator ,则从 SortedSet<String> 转换为 String[] 时。

映射 to Java 类型 from 开放类型的问题用 InvalidObjectException 表示。在分析 MXBean 接口时可能会发生这种情况,例如,如果根据上述规则它引用的类型不是 reconstructible,在需要可重构类型的上下文中。或者在转换实例(MXBean 中方法的参数或 MXBean 代理中方法的返回值)时发生,例如,如果没有具有该名称的 Enum 常量,则从 String 转换为 Enum。

根据上下文,OpenDataExceptionInvalidObjectException 可能包含在另一个异常中,例如 RuntimeMBeanException UndeclaredThrowableException 。对于每个抛出的异常,条件 C 将为真:“e OpenDataExceptionInvalidObjectException(视情况而定),或者 Ce .getCause() 为真”。

自从:
1.6
  • 可选元素摘要

    可选元素
    修饰符和类型
    可选元素
    描述
    boolean
    如果带注解的接口是 MXBean 接口,则为真。
  • 元素详细信息

    • value

      boolean value
      如果带注解的接口是 MXBean 接口,则为真。
      返回:
      如果带注解的接口是 MXBean 接口,则为 true。
      默认:
      true