Module java.management
Package javax.management

Annotation Interface 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概念提供了一种简单的方式来编写仅引用预定义类型集的MBean,这些类型由javax.management.openmbean定义。通过这种方式,您可以确保您的MBean可被任何客户端(包括远程客户端)使用,而无需客户端访问表示您的MBeans类型的特定于模型的类

通过与标准MBean概念进行比较,这些概念更容易理解。下面是如何将托管对象表示为标准MBean和MXBean的方式:

标准MBean

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

MXBean

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

如您所见,这些定义非常相似。唯一的区别是,命名接口的约定是对于MXBeans使用SomethingMXBean,而不是对于标准MBeans使用SomethingMBean

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

因此,我们可以这样定义MemoryUsage

标准MBean

public class MemoryUsage implements Serializable {
    // 遵循标准的JavaBean约定,包括getter方法

    public MemoryUsage(long init, long used,
                       long committed, long max) {...}
    long getInit() {...}
    long getUsed() {...}
    long getCommitted() {...}
    long getMax() {...}
}
        

MXBean

public class MemoryUsage {
    // 遵循标准的JavaBean约定,包括getter方法
    @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是一个特定于模型的类。对于标准MBeans,MBean服务器的客户端如果不知道类MemoryUsage,则无法访问Usage属性。假设客户端是基于JMX技术的通用控制台。那么控制台必须配置每个可能连接的应用程序的特定于模型的类。对于非用Java语言编写的客户端,问题甚至更严重。那时可能没有办法告诉客户端MemoryUsage是什么样子。

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

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

标准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这样的简单类型的属性,代码是相同的。但对于具有复杂类型的属性,标准MBean代码要求客户端知道模型特定类MemoryUsage,而MXBean代码不需要非标准类。

这里显示的客户端代码对于MXBean客户端稍微更复杂。但是,如果客户端实际上知道模型,这里是接口MemoryPoolMXBean和类MemoryUsage,那么它可以构建一个代理。这是在事先知道模型时与托管对象交互的推荐方式,无论您是使用标准MBeans还是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对象的实现对标准MBeans和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注册到MBean服务器中的方式是相同的:

标准MBean

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

MXBean

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

MXBean的定义

MXBean是一种MBean。MXBean对象可以直接注册到MBean服务器中,或者可以用作StandardMBean的参数,并将生成的MBean注册到MBean服务器中。

当使用MBeanServer接口的registerMBeancreateMBean方法将对象注册到MBean服务器中时,将检查对象的类以确定它是哪种类型的MBean:

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

每个在MXBean接口中作为方法参数或返回类型出现的Java类型必须符合以下规则进行可转换。此外,参数必须按照以下定义进行可重构

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

命名约定

在MXBean中,方法的命名约定与标准MBean中的方法相同:

  1. 一个方法T getN(),其中T是一个Java类型(不是void),N是一个非空字符串,指定存在一个可读属性称为N。属性的Java类型和Open类型由以下映射规则确定。继承自 Object的方法final Class getClass()在查找getter时会被忽略。
  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类型进行描述,即OpenType的四个标准子类。MXBean通过将Java类型映射到Open类型来实现这一点。

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

  • 对应的Open类型,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类型,允许使用空值,除了原始Java类型,其中不可能使用空值。在从类型J转换为类型opendata(J)或从类型opendata(J)转换为类型J时,空值映射为空值。

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

E []相同 E []相同
类型映射规则
Java类型J opentype(J) opendata(J)
intboolean,等等
(8个原始Java类型)
SimpleType.INTEGER
SimpleType.BOOLEAN,等等
IntegerBoolean,等等
(对应的包装类型)
IntegerObjectName,等等
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
(在Java中声明为enum E {...}
SimpleType.STRING String
Map<K,V>
SortedMap<K,V>
TabularType
(见下文)
TabularData
(见下文)
记录类 CompositeType,如果可能
(见下文)
CompositeData
(见下文)
一个MXBean接口 SimpleType.OBJECTNAME
(见下文)
ObjectName
(见下文)
任何其他类型 CompositeType,如果可能
(见下文)
CompositeData
(见下文)

以下部分提供了这些规则的进一步细节。

原始类型的映射

8个原始Java类型(booleanbyteshortint longfloatdoublechar)被映射到java.lang中对应的包装类型,即 BooleanByte等。Open类型是相应的SimpleType。因此,opentype( long)SimpleType.LONGopendata(long) java.lang.Long

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

实际上,在JMX API中,操作始终针对Java对象而不是原始类型。但是,数组之间的区别是存在的。

集合的映射(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实例具有非空comparator(),则将使用IllegalArgumentException失败。

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

映射到地图的映射(Map<K,V>等)

例如,Map<K,V>SortedMap<K,V>,例如 Map<String,ObjectName>,具有开放类型TabularType,并映射到TabularDataTabularType有两个名为keyvalue的项。 key的开放类型是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实例具有非空的comparator(),则转换将失败并引发IllegalArgumentException

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

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

记录的映射

记录类J只有当其所有组件都可以转换为开放类型时才能转换为CompositeType。否则,它是不可转换的。没有组件的记录是不可转换的。

将记录类映射到CompositeType

如果记录的所有组件都可以转换为开放类型,则记录本身可以转换为CompositeType。记录类转换为CompositeType如下。

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

将记录类的实例映射到CompositeData

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

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服务器中注册为MXBean。

方法ModuleMXBean.getProduct()定义了一个名为Product的属性。此属性的开放类型是SimpleType.OBJECTNAME,相应的ObjectName值将是在MBean服务器中注册的引用的ProductMXBean的名称。

如果您为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服务器中注册并尝试在同一MBean服务器中使用另一个名称注册它,则结果是InstanceAlreadyExistsException。通常不建议在同一MBean服务器中将相同的MBean对象注册多次,特别是因为对于是NotificationBroadcaster的MBean,这样做效果不佳。

其他类型的映射

给定一个不符合上表中其他规则的Java类或接口J,MXBean框架将尝试将其映射到CompositeType,如下所示。此CompositeType的类型名称由下面的类型名称规则确定。

将Java类型J映射到CompositeType

检查类以查找使用上面的约定getter。 (Getter必须是公共实例方法。)如果没有getter,或者如果任何getter具有不可转换的类型,则J是不可转换的。

如果至少有一个getter,并且每个getter都具有可转换的类型,则opentype(J)是一个CompositeType,其中每个getter都有一个项目。如果getter是

T getName()
那么CompositeType中的项目称为name,其类型为opentype(T)。例如,如果项目是
String getOwner()
那么项目称为owner,其开放类型为SimpleType.STRING。如果getter是
boolean isName()
那么CompositeType中的项目称为name,其类型为SimpleType.BOOLEAN

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

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

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

当开放类型为CompositeType时,相应的映射的Java类型(opendata(J))是CompositeData。从J的实例到与刚刚描述的CompositeType对应的CompositeData的映射如下进行。首先,如果J实现了接口CompositeDataView,那么将调用该接口的toCompositeData方法来进行转换。否则,通过调用每个项的getter并将其转换为相应的开放数据类型来构造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中,则规范构造函数是适用的

  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注解中提及的getter不会导致错误(这些可能对应于不需要重建对象的信息)。

    通过使用适当重建的项从CompositeData调用构造函数来重建J的实例。将在运行时基于实际存在于CompositeData中的项确定要调用的构造函数,考虑到此CompositeData可能来自J的早期版本,其中并非所有项都存在。如果没有适用的构造函数,则尝试重建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的早期版本,某些项可能不存在。在这种情况下,将不会调用相应的setter。

  5. 否则,如果J是一个除了getter之外没有其他方法的接口,则将使用由CompositeData支持的CompositeData作为后端的Proxy构造J的实例。

  6. 否则,J不可重建。

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

以下是展示不同编码类型NamedNumber的不同方式的示例,该类型由一个int和一个String组成。在每种情况下,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. 每个getter都有setter:
    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. 只有getter的接口:
    public interface NamedNumber {
        public int getNumber();
        public String getName();
    }
              

对于仅表示数据集合的类,最好是不可变的。不可变类的实例在构造后无法更改。请注意,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。特别是,当属性、参数或操作返回值的类型是原始类型,如int,或是void(对于返回类型),那么属性、参数或操作将分别由一个MBeanAttributeInfoMBeanParameterInfoMBeanOperationInfo表示,其getType()getReturnType()返回原始名称("int"等)。即使映射规则指定opendata映射是包装类型(Integer等),也是如此。

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

对于直接在MBean服务器中注册的MXBean,MBeanInfo.getNotifications()返回的通知类型数组如果MXBean没有实现NotificationBroadcaster接口,则为空。否则,它将是在注册MXBean时调用NotificationBroadcaster.getNotificationInfo()的结果。即使此方法的结果随后发生更改,MBeanInfo.getNotifications()的结果也不会改变。对于使用StandardMBeanStandardEmitterMBean类构造的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[]>"表示。

异常

从Java类型Open类型的映射存在问题时,会使用OpenDataException发出信号。这可能发生在分析MXBean接口时,例如,如果引用了没有getter的类型,如java.util.Random。或者当实例被转换时(从MXBean中的方法返回值或MXBean代理中的方法参数),例如,当从SortedSet<String>转换为 String[]时,如果SortedSet具有非空Comparator

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

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

自从:
1.6
  • Optional Element Summary

    Optional Elements
    Modifier and Type
    Optional Element
    Description
    boolean
    如果注解的接口是MXBean接口,则为True。
  • Element Details

    • value

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