Интерфейс аннотации MXBean
@Documented @Retention(RUNTIME) @Target(TYPE) public @interface MXBean
Аннотация для явного обозначения интерфейса как интерфейса MXBean или как интерфейса, не являющегося MXBean. По умолчанию, интерфейс является интерфейсом MXBean, если он является публичным и его имя заканчивается на MXBean, как в SomethingMXBean. Следующие интерфейсы являются интерфейсами 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 будет пригоден для любого клиента, включая удалённых клиентов, без каких-либо требований, что клиент имеет доступ к модель-специфическим классам, представляющим типы ваших MBean.
Концепции легче понять по сравнению с концепцией Standard MBean. Вот как управляемый объект может быть представлен как Standard MBean и как MXBean:
Standard MBean
public interface MemoryPoolMBean {
String getName();
MemoryUsage getUsage();
// ...
}
MXBean
public interface MemoryPoolMXBean {
String getName();
MemoryUsage getUsage();
// ...
}
Как вы можете видеть, определения очень похожи. Единственное различие заключается в том, что соглашение об именовании интерфейса использует SomethingMXBean для MXBean, а не SomethingMBean для Standard MBean.
В этом управляемом объекте есть атрибут, называемый Usage типа MemoryUsage. Суть такого атрибута в том, что он предоставляет согласованный снимок набора элементов данных. Например, он может включать текущее количество используемой памяти в пуле памяти и текущий максимум пула памяти. Если бы эти были отдельными элементами, полученными с помощью отдельных вызовов getAttribute, то мы могли бы получить значения, увиденные в разное время, которые не были бы согласованными. Мы могли бы получить значение used, которое было бы больше, чем значение max.
Итак, мы могли бы определить MemoryUsage так:
Standard 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 для связи параметров конструктора с соответствующими геттерами. Мы подробнее рассмотрим это ниже.
MemoryUsage — это модель-специфический класс. В случае Standard MBean клиент MBean Server не может получить доступ к атрибуту Usage, если он не знает класс MemoryUsage. Предположим, клиент — это общая консоль, основанная на технологии JMX. Тогда консоль должна быть настроена с модель-специфическими классами каждого приложения, к которому она может подключиться. Проблема ещё хуже для клиентов, которые не написаны на языке Java. Тогда может не быть способа сказать клиенту, как выглядит MemoryUsage.
В этом MXBean отличается от Standard MBean. Хотя мы определяем интерфейс управления почти таким же образом, платформа MXBean преобразует модель-специфические классы в стандартные классы платформы Java. Используя массивы и классы CompositeData и TabularData из стандартного пакета javax.management.openmbean, можно создавать структуры данных произвольной сложности, используя только стандартные классы.
Это становится яснее, если сравнить, как могут выглядеть клиенты обеих моделей:
Standard 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, то он может создать прокси. Это рекомендуемый способ взаимодействия с управляемыми объектами, когда заранее известна модель, независимо от того, используете ли вы Standard MBean или MXBean:
Standard 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 работает аналогично как для Standard MBean, так и для MXBean.
Standard 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 Server происходит одинаково в обоих случаях:
Standard 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 зарегистрирован в MBean Server.
Когда объект регистрируется в MBean Server с помощью методов registerMBean или createMBean интерфейса MBeanServer, класс объекта проверяется для определения типа MBean:
- Если класс реализует интерфейс
DynamicMBean, то MBean является Dynamic MBean. Обратите внимание, что классStandardMBeanреализует этот интерфейс, поэтому этот случай применим к Standard MBean или MXBean, созданным с помощью классаStandardMBean. - В противном случае, если класс соответствует соглашениям об именовании Standard MBean, то MBean является Standard MBean.
- В противном случае, это может быть MXBean. Проверяется набор реализованных объектом интерфейсов на наличие интерфейсов:
- имеющих имя класса
SMXBean, гдеS— любая непустая строка и не имеющих аннотации@MXBean(false); и/или - имеющих аннотацию
@MXBean(true)или просто@MXBean.
MemoryPoolMXBean. - имеющих имя класса
- Если ни одно из этих условий не выполнено, MBean недействителен, и попытка его регистрации сгенерирует
NotCompliantMBeanException.
Каждый Java-тип, который появляется как параметр или возвращаемый тип метода в интерфейсе MXBean, должен быть преобразуем в соответствии с нижеприведёнными правилами. Кроме того, параметры должны быть восстановимы, как определено ниже.
Попытка создать MXBean, который не соответствует вышеперечисленным правилам, вызовет исключение.
Соглашения об именовании
Те же соглашения об именовании применяются к методам в MXBean, что и в Standard MBean:
- Метод
T getN(), гдеT— это Java-тип (неvoid) иN— непустая строка, указывает на то, что есть читабельный атрибут, называемыйN. Java-тип и тип Open определяются правилами сопоставления ниже. Методfinal Class getClass(), унаследованный отObject, игнорируется при поиске геттеров. - Метод
boolean isN()указывает на то, что существует читабельный атрибут, называемыйN, с Java-типомbooleanи типом OpenSimpleType.Boolean. - Метод
void setN(T x)указывает на то, что существует записываемый атрибут, называемыйN. Java-тип и тип Open атрибута определяются правилами сопоставления ниже. (Конечно, имяxпараметра не имеет значения.) - Все остальные методы указывают на то, что есть операция с тем же именем, что и метод. Java-тип и тип Open возвращаемого значения и каждого параметра определяются правилами сопоставления ниже.
Правила для getN и isN вместе определяют понятие геттера. Правило для setN определяет понятие сеттера.
Ошибка — это наличие двух геттеров с одинаковым именем или двух сеттеров с одинаковым именем. Если есть геттер и сеттер с одинаковым именем, то тип T в обоих должен быть одинаковым. В этом случае атрибут является читаемым/записываемым. Если есть только геттер или только сеттер, атрибут является только для чтения или только для записи соответственно.
Правила сопоставления типов
MXBean является типом Open MBean, как определено пакетом javax.management.openmbean. Это означает, что типы атрибутов, параметров операций и возвращаемых значений операций должны быть описываемы с использованием Open Types, то есть четырёх стандартных подклассов OpenType. MXBean достигают этого, сопоставляя Java-типы с Open Types.
Для каждого Java-типа J, сопоставление MXBean описывается следующей информацией:
- Соответствующий тип Open, opentype(J). Это экземпляр подкласса
OpenType. - Сопоставленный Java-тип, opendata(J), который всегда одинаков для любого данного opentype(J). Это Java-класс.
- Как значение преобразуется из типа J в тип opendata(J).
- Как значение преобразуется из типа opendata(J) в тип J, если это возможно.
Например, для типа Java List<String>:
- Тип Открытый тип, opentype(
List<String>), являетсяArrayType(1,SimpleType.STRING), представляющим одномерный массивString. - Сопоставленный тип Java, opendata(
List<String>), этоString[]. List<String>можно преобразовать вString[], используяList.toArray(new String[0]).String[]можно преобразовать вList<String>, используяArrays.asList.
Если правила сопоставления для получения opentype(J) из J отсутствуют, то J не может быть типом параметра или возвращаемого значения метода в интерфейсе MXBean.
Если существует способ преобразовать opendata(J) обратно в J, то мы говорим, что J является восстанавливаемым. Все параметры метода в интерфейсе 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[][], где E есть int[]) |
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(см. ниже) |
| Классы записей |
CompositeType, если возможно(см. ниже) |
CompositeData(см. ниже) |
| Интерфейс MXBean |
SimpleType.OBJECTNAME(см. ниже) |
ObjectName(см. ниже) |
| Любой другой тип |
CompositeType, если возможно(см. ниже) |
CompositeData(см. ниже) |
В следующих разделах приведены дополнительные сведения об этих правилах.
Сопоставления для примитивных типов
8 примитивных типов Java (boolean, byte, short, int,
long, float, double, char) сопоставляются с соответствующими упакованными типами из java.lang, а именно
Boolean, Byte и т. д. Открытый тип — соответствующий SimpleType. Таким образом, opentype(
long) является SimpleType.LONG, а opendata(long) является
java.lang.Long.
Массив примитивного типа, например, long[], можно напрямую представить как Открытый тип. Таким образом, openType(
long[]) является
ArrayType.getPrimitiveArrayType(long[].class), а opendata(long[]) является
long[].
На практике различие между обычным int и
Integer и т. д. не проявляется, потому что операции в API JMX всегда выполняются над объектами 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 завершится ошибкой IllegalArgumentException, если у него есть непустой comparator().
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 и сопоставляется с TabularData. TabularType содержит два элемента, называемые key и value. Открытый тип key — opentype(K), а Открытый тип value — opentype(V). Индекс TabularType — единственный элемент key.
Например, TabularType для
Map<String,ObjectName> может быть создан кодом такого типа:
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<K,V> как Открытых данных, это TabularDataSupport или другой класс, реализующий
TabularData, который сериализуется как TabularDataSupport.
Сопоставления для записей
Класс записей record J может быть преобразован в CompositeType только в том случае, если все его компоненты преобразуются в открытые типы. В противном случае он не преобразуется. Запись без компонентов не преобразуется.
Сопоставление класса записей с CompositeType
Запись, компоненты которой могут быть преобразованы в открытые типы, сама может быть преобразована в CompositeType. Класс записи преобразуется в CompositeType следующим образом.
- Имя типа
CompositeType— это имя класса записи. - Геттеры записи — это методы доступа к компонентам записи.
- Для каждого компонента записи типа T элемент в
CompositeTypeимеет то же имя, что и компонент записи, и его тип — opentype(T), как определено в правилах сопоставления типов выше.
Сопоставление экземпляра класса записи с CompositeData
Сопоставление экземпляра класса записи с CompositeData, соответствующему CompositeType, совпадает с тем, что указано для других типов.
Восстановление экземпляра класса записи из CompositeData
Запись восстанавливается с помощью её канонического конструктора. Канонический конструктор не требует наличия @javax.management.ConstructorParameters или @java.beans.ConstructorProperties аннотаций. Если эти аннотации присутствуют в каноническом конструкторе, они будут проигнорированы.
Подробное описание восстановления экземпляра класса записи J из CompositeData приведено в разделе Восстановление экземпляра типа Java или класса записи J из CompositeData ниже.
Сопоставления для интерфейсов MXBean
Интерфейс MXBean или тип, на который ссылается интерфейс MXBean, может ссылаться на другой интерфейс MXBean, J. В этом случае opentype(J) — это SimpleType.OBJECTNAME, а opendata(J) — это ObjectName.
Например, предположим, что у вас есть два интерфейса MXBean, как это:
public interface ProductMXBean {
public ModuleMXBean[] getModules();
}
public interface ModuleMXBean {
public ProductMXBean getProduct();
}
Объект, реализующий интерфейс ModuleMXBean, возвращает из своего метода getProduct объект, реализующий интерфейс ProductMXBean. Объект ModuleMXBean и возвращённые объекты
ProductMXBean должны быть зарегистрированы как MXBeans в одном и том же сервере MBean.
Метод ModuleMXBean.getProduct() определяет атрибут, называемый Product. Открытый тип для этого атрибута — SimpleType.OBJECTNAME, а соответствующее значение ObjectName будет именем, под которым эта ссылка ProductMXBean зарегистрирована в сервере MBean.
Если вы создадите прокси MXBean для ModuleMXBean и вызовете его метод getProduct(), прокси будет преобразовывать ObjectName обратно в ProductMXBean, создавая ещё один прокси MXBean. Более формально, когда прокси, созданный с помощью 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 должен быть преобразован в объект ProductMXBean, который ожидается методом setProduct. Этот объект будет прокси MXBean для данного ObjectName в том же сервере MBean.
Если вы создадите прокси MXBean для ModuleMXBean и вызовете его метод setProduct, прокси преобразует аргумент ProductMXBean обратно в ObjectName. Это сработает только в том случае, если аргумент фактически является другим прокси для ProductMXBean в том же
MBeanServerConnection. Прокси может быть возвращен другим прокси (например, ModuleMXBean.getProduct(), который возвращает прокси для ProductMXBean); или он может быть создан с помощью JMX.newMXBeanProxy; или он может быть создан с помощью Proxy с обработчиком вызовов, который является MBeanServerInvocationHandler или его подклассом.
Если один и тот же MXBean зарегистрирован под двумя разными ObjectName, ссылка на этот MXBean из другого MXBean будет неоднозначной. Поэтому, если объект MXBean уже зарегистрирован в сервере MBean, и делается попытка зарегистрировать его в том же сервере MBean под другим именем, результатом будет InstanceAlreadyExistsException. В общем случае не рекомендуется регистрировать один и тот же объект MBean под несколькими именами, особенно потому, что это не работает с MBeans, которые являются NotificationBroadcaster.
Сопоставления для других типов
Учитывая класс или интерфейс Java J, который не соответствует другим правилам в таблице выше, платформа MXBean попытается сопоставить его с CompositeType следующим образом. Имя типа этого CompositeType определяется правилами именования типов ниже.
Сопоставление типа Java J с CompositeType
Класс проверяется на наличие геттеров с использованием приведенных выше соглашений. (Геттеры должны быть открытыми методами экземпляра.) Если геттеров нет или тип любого геттера не может быть преобразован, то J не может быть преобразован.
Если есть хотя бы один геттер и тип каждого геттера может быть преобразован, то opentype(J) — это
CompositeType с одним элементом для каждого геттера. Если геттер
T getName() то элемент в CompositeType называется name и имеет тип opentype(T). Например, если элемент — String getOwner() то элемент называется owner и имеет открытый тип
SimpleType.STRING. Если геттер — boolean isName() то элемент в CompositeType называется name и имеет тип SimpleType.BOOLEAN. Обратите внимание, что первая буква (или символ) преобразуется в нижний регистр. Это соответствует соглашению Java Beans, которое по историческим причинам отличается от соглашения Standard MBean. В интерфейсе Standard MBean или MXBean метод getOwner определяет атрибут, называемый Owner, а в интерфейсе Java Bean или сопоставленном CompositeType методе
getOwner определяет свойство или элемент, называемый owner.
Если два метода производят одно и то же имя элемента (например,
getOwner и isOwner, или getOwner и
getowner), то тип не может быть преобразован.
Преобразование экземпляра типа Java или класса записи J в CompositeData
Когда открытый тип — CompositeType, соответствующий сопоставленный тип Java (opendata(J)) — CompositeData. Сопоставление экземпляра J с CompositeData, соответствующим CompositeType, описанному выше, выполняется следующим образом. Во-первых, если J реализует интерфейс CompositeDataView, то вызывается метод toCompositeData этого интерфейса для выполнения преобразования. В противном случае CompositeData создается путём вызова геттера для каждого элемента и преобразования его в соответствующий тип открытых данных. Таким образом, геттер, такой как
List<String> getNames()(илиList<String> names()для записи)
будет сопоставлен элементу с именем "names" и открытым типом CompositeData. Преобразование в CompositeData вызовет getNames() и преобразует полученный List<String> в String[] для элемента "names".
CompositeData — это интерфейс. Конкретный класс, используемый для представления типа в виде открытых данных, — это CompositeDataSupport, или другой класс, реализующий
CompositeData, который сериализуется как
CompositeDataSupport.
Восстановление экземпляра типа Java или класса записи J из CompositeData
Если opendata(J) — это CompositeData для типа Java J, то экземпляр J может быть восстановлен из CompositeData, или J не подлежит восстановлению. Если какой-либо элемент в CompositeData не подлежит восстановлению, то J тоже не подлежит восстановлению.
Для любого заданного J будут рассмотрены следующие правила, чтобы определить, как восстановить экземпляры J из CompositeData. Будет использовано первое применимое правило в списке.
Если у J есть метод
public staticJfrom(CompositeData cd)
то этот метод вызывается для реконструкции экземпляра J.В противном случае, если J является классом
Record, и применимый канонический конструктор записи, экземпляр J реконструируется путём вызова канонического конструктора записи. Канонический конструктор, если применим, вызывается с соответствующими реконструированными элементами изCompositeData. Канонический конструктор применим, если все свойства, указанные компонентами записи, присутствуют вCompositeData.-
В противном случае, если у J есть хотя бы один публичный конструктор с аннотацией
@javax.management.ConstructorParametersили аннотацией@java.beans.ConstructorProperties, то один из этих конструкторов (не обязательно всегда один и тот же) будет вызван для реконструкции экземпляра J. Если конструктор аннотирован и аннотацией@javax.management.ConstructorParametersи аннотацией@java.beans.ConstructorProperties, то будет использована@javax.management.ConstructorParameters, а@java.beans.ConstructorPropertiesбудет проигнорирована. Каждая такая аннотация должна содержать столько строк, сколько параметров у конструктора; каждая строка должна указывать свойство, соответствующее геттеру J; и тип этого геттера должен быть таким же, как у соответствующего параметра конструктора. Не является ошибкой наличие геттеров, которые не упоминаются в аннотациях@ConstructorParametersили@ConstructorProperties(они могут соответствовать информации, которая не нужна для реконструкции объекта).Экземпляр J реконструируется путём вызова конструктора с соответствующими реконструированными элементами из
CompositeData. Конструктор, который будет вызван, будет определяться во время выполнения на основе фактически присутствующих элементов вCompositeData, учитывая, что этотCompositeDataможет исходить из более ранней версии J, где не все элементы были присутствуют. Конструктор применим, если все свойства, указанные в его аннотации@ConstructorParametersили@ConstructorProperties, присутствуют в качестве элементов вCompositeData. Если ни один конструктор не применим, попытка реконструировать J завершится неудачно.Для любой возможной комбинации свойств должно выполняться одно из следующих условий: (а) нет применимых конструкторов, или (б) есть ровно один применимый конструктор, или (в) один из применимых конструкторов указывает надмножество свойств, указанных каждым другим применимым конструктором. (Другими словами, не должно быть неоднозначности в выборе конструктора). Если это условие не выполняется, то J не подлежит реконструкции.
-
В противном случае, если у J есть публичный конструктор без аргументов и для каждого геттера в J с типом T и именем N есть соответствующий сеттер с тем же именем и типом, то экземпляр J создаётся с помощью конструктора без аргументов, а сеттеры вызываются с реконструированными элементами из
CompositeDataдля восстановления значений. Например, если есть метод
public List<String> getNames()
то также должен быть метод
public void setNames(List<String> names)
для применения этого правила.Если
CompositeDataпришел из более ранней версии J, некоторые элементы могут отсутствовать. В этом случае соответствующие сеттеры не будут вызваны. В противном случае, если J — интерфейс, у которого нет методов, кроме геттеров, экземпляр J создаётся с помощью
ProxyсCompositeDataInvocationHandler, поддерживаемымCompositeData, который преобразуется.В противном случае, J не подлежит реконструкции.
Правило 2 не применимо, когда java.beans.ConstructorProperties не виден (например, когда модуль java.desktop не читается или когда образ выполнения не содержит модуль java.desktop). При нацеливании на среду выполнения, которая не включает пакет 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 );
- Статический
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; } - Запись:
public record NamedNumber(int number, String name) {} - Публичный конструктор с аннотацией
@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; } - Сеттер для каждого геттера:
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; } - Интерфейс только с геттерами:
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();
}
Содержание MBeanInfo для MXBean
MXBean — это тип Open MBean. Однако по соображениям совместимости его MBeanInfo не является OpenMBeanInfo. В частности, когда тип атрибута, параметра или возвращаемого значения операции является примитивным типом, таким как int, или является void (для типа возвращаемого значения), то атрибут, параметр или операция будут соответственно представлены MBeanAttributeInfo, MBeanParameterInfo или MBeanOperationInfo, чья getType() или
getReturnType() возвращает имя примитива ("int" и т.д.). Это так даже несмотря на то, что правила сопоставления выше указывают, что отображение opendata — это обернутый тип (Integer и т.д.).
Массив публичных конструкторов, возвращаемых MBeanInfo.getConstructors() для MXBean, который зарегистрирован непосредственно в MBean Server, будет содержать все публичные конструкторы этого MXBean. Если класс MXBean не является публичным, то и его конструкторы не считаются публичными. Список, возвращаемый для MXBean, созданного с помощью класса StandardMBean, выводится аналогичным образом, как для Standard MBean. Независимо от того, как был создан MXBean, его параметры конструктора не подлежат правилам сопоставления MXBean и не имеют соответствующего OpenType.
Массив типов уведомлений, возвращаемых MBeanInfo.getNotifications() для MXBean, который зарегистрирован непосредственно в MBean Server, будет пустым, если MXBean не реализует интерфейс NotificationBroadcaster. В противном случае, он будет результатом вызова NotificationBroadcaster.getNotificationInfo() в момент регистрации MXBean. Даже если результат этого метода изменяется впоследствии, результат MBeanInfo.getNotifications() не изменится. Список, возвращаемый для MXBean, созданного с помощью класса StandardMBean или StandardEmitterMBean, выводится аналогичным образом, как для Standard MBean.
Описание Descriptor для всех MBeanAttributeInfo, MBeanParameterInfo и MBeanOperationInfo объектов, содержащихся в MBeanInfo, будет иметь поле openType, значение которого равно OpenType, указанной правилами сопоставления выше. Таким образом, даже когда getType() равно "int", getDescriptor().getField("openType") будет SimpleType.INTEGER.
Descriptor для каждого из этих объектов также будет иметь поле originalType, которое представляет собой строку, представляющую тип Java, который появился в интерфейсе MXBean. Формат этой строки описан в разделе Имена типов ниже.
Descriptor для MBeanInfo будет иметь поле mxbean, значение которого равно строке "true".
Имена типов
Иногда неотображённый тип T параметра или возвращаемого значения метода в MXBean должен быть представлен в виде строки. Если 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[], это будет представлено строкой "[I", возвращаемой
Class.getName(), но если метод возвращает List<int[]>, это будет представлено строкой
"java.util.List<int[]>".
Исключения
Проблема с отображением из типов Java в типы Open сигнализируется исключением OpenDataException. Это может произойти при анализе интерфейса MXBean, например, если он ссылается на тип, как java.util.Random, у которого нет методов-геттеров. Или это может произойти при преобразовании экземпляра (значение, возвращаемое методом в MXBean или параметр метода в прокси MXBean), например, при преобразовании из SortedSet<String> в
String[], если SortedSet имеет непустой
Comparator.
Проблема с отображением в типы Java из типов Open сигнализируется исключением InvalidObjectException. Это может произойти при анализе интерфейса MXBean, например, если он ссылается на тип, который не является восстановимым в соответствии с вышеуказанными правилами, в контексте, где требуется восстанавливаемый тип. Или это может произойти при преобразовании экземпляра (параметр метода в MXBean или возвращаемое значение метода в прокси MXBean), например, из String в Enum, если нет константы Enum с таким именем.
В зависимости от контекста, исключение OpenDataException или InvalidObjectException может быть обернуто в другое исключение, например, RuntimeMBeanException или UndeclaredThrowableException. Для каждого сгенерированного исключения условие C будет истинным: «e является
OpenDataException или InvalidObjectException (в зависимости от контекста) или условие C истинно для e.getCause()».
- Since:
- 1.6
Краткое описание необязательных элементов
| Модификатор и тип | Необязательный элемент | Описание |
|---|---|---|
boolean |
value |
Истинно, если аннотированный интерфейс является интерфейсом MXBean. |
Подробное описание элементов
value
boolean value
- Возвращает:
- Истинно, если аннотированный интерфейс является интерфейсом MXBean.
- Значение по умолчанию:
true
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.management/javax/management/MXBean.html