Аннотация-интерфейс MXBean
@Documented @Retention(RUNTIME) @Target(TYPE) public @interface MXBean
Аннотация, явно указывающая, что интерфейс является интерфейсом MXBean или не является им. По умолчанию интерфейс является интерфейсом MXBean, если он объявлен как public и его имя заканчивается на 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.
Эти понятия проще понять, сравнив их с концепцией стандартного MBean. Вот как управляемый объект может быть представлен в виде стандартного MBean и MXBean:
Стандартный MBean
public interface MemoryPoolMBean {
String getName();
MemoryUsage getUsage();
// ...
}
MXBean
public interface MemoryPoolMXBean {
String getName();
MemoryUsage getUsage();
// ...
}
Как видно, определения очень похожи. Единственное отличие — соглашение об именовании интерфейса: для MXBean используется SomethingMXBean, а для стандартных MBean — SomethingMBean.
У этого управляемого объекта есть атрибут Usage типа MemoryUsage. Такой атрибут позволяет получить согласованный снимок набора элементов данных. Например, он может содержать текущий объём использованной памяти в пуле памяти и его текущий максимальный размер. Если бы это были отдельные элементы, получаемые отдельными вызовами getAttribute, мы могли бы получить значения, снятые в разное время и потому несогласованные. Например, значение used могло бы оказаться больше значения max.
Итак, мы могли бы определить 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, чтобы связать параметры конструктора с соответствующими методами получения. Подробнее об этом будет сказано ниже.
MemoryUsage — это класс, специфичный для модели. При использовании стандартных MBean клиент сервера MBean не может получить доступ к атрибуту Usage, если ему неизвестен класс MemoryUsage. Представим, что клиент — это универсальная консоль, основанная на технологии JMX. Тогда для работы консоли пришлось бы настроить классы, специфичные для модели, каждого приложения, к которому она может подключиться. Для клиентов, написанных не на языке Java, проблема ещё серьёзнее: может не существовать способа сообщить такому клиенту, как выглядит MemoryUsage.
Именно здесь MXBean отличаются от стандартных MBean. Хотя интерфейс управления определяется почти точно так же, инфраструктура MXBean преобразует классы, специфичные для модели, в стандартные классы платформы Java. Используя массивы, а также классы CompositeData и TabularData из стандартного пакета javax.management.openmbean, можно создавать структуры данных произвольной сложности, используя только стандартные классы.
Это становится понятнее, если сравнить, как могут выглядеть клиенты обеих моделей:
Стандартный 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, — он может создать прокси. Это рекомендуемый способ взаимодействия с управляемыми объектами, если модель известна заранее, независимо от того, используются стандартные MBean или MXBean:
Стандартный 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 и MXBean.
Стандартный 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.
Когда объект регистрируется на сервере MBean с помощью методов registerMBean или createMBean интерфейса MBeanServer, класс объекта проверяется, чтобы определить тип MBean:
- Если класс реализует интерфейс
DynamicMBean, то MBean является динамическим MBean. Обратите внимание, что классStandardMBeanреализует этот интерфейс, поэтому этот случай относится к стандартному MBean или MXBean, созданному с помощью классаStandardMBean. - В противном случае, если класс соответствует соглашениям об именовании стандартных MBean, MBean является стандартным MBean.
- В противном случае это может быть MXBean. Среди интерфейсов, реализованных объектом, проверяются те, которые:
- имеют имя класса
SMXBean, гдеS— любая непустая строка, и не имеют аннотации@MXBean(false); и/или - имеют аннотацию
@MXBean(true)или просто@MXBean.
MemoryPoolMXBean. - имеют имя класса
- Если ни одно из этих условий не выполнено, MBean считается недопустимым, и попытка его регистрации приведёт к исключению
NotCompliantMBeanException.
Каждый тип Java, используемый в качестве типа параметра или возвращаемого значения метода интерфейса MXBean, должен быть преобразуемым согласно приведённым ниже правилам. Кроме того, параметры должны быть восстанавливаемыми, как определено ниже.
Попытка создать MXBean, не соответствующий приведённым выше правилам, приведёт к исключению.
Соглашения об именовании
Для методов MXBean применяются те же соглашения об именовании, что и для стандартных MBean:
- Метод
T getN(), гдеT— тип Java (неvoid), аN— непустая строка, указывает на наличие доступного для чтения атрибута с именемN. Тип Java и открытый тип атрибута определяются приведёнными ниже правилами сопоставления. Методfinal Class getClass(), унаследованный отObject, при поиске методов получения игнорируется. - Метод
boolean isN()указывает на наличие доступного для чтения атрибута с именемN, типом Javabooleanи открытым типомSimpleType.Boolean. - Метод
void setN(T x)указывает на наличие доступного для записи атрибута с именемN. Тип Java и открытый тип атрибута определяются приведёнными ниже правилами сопоставления. (Разумеется, имя параметраxне имеет значения.) - Каждый другой метод указывает на наличие операции с тем же именем, что и у метода. Тип Java и открытый тип возвращаемого значения и каждого параметра определяются приведёнными ниже правилами сопоставления.
Правила для getN и isN вместе определяют понятие метода получения. Правило для setN определяет понятие метода задания.
Наличие двух методов получения с одинаковым именем или двух методов задания с одинаковым именем является ошибкой. Если для одного имени есть метод получения и метод задания, то тип T в обоих случаях должен совпадать. Тогда атрибут доступен и для чтения, и для записи. Если есть только метод получения или только метод задания, атрибут доступен соответственно только для чтения или только для записи.
Правила сопоставления типов
MXBean — это разновидность открытого MBean, определённого в пакете javax.management.openmbean. Это означает, что типы атрибутов, параметров операций и возвращаемых значений операций должны описываться с помощью открытых типов, то есть четырёх стандартных подклассов OpenType. MXBean обеспечивают это, сопоставляя типы Java с открытыми типами.
Для каждого типа Java J сопоставление MXBean описывается следующими сведениями:
- Соответствующий открытый тип, 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 и открытых типов допускаются значения null, за исключением примитивных типов Java, для которых они невозможны. При преобразовании из типа J в тип opendata(J) или из типа opendata(J) в тип J значение null преобразуется в значение null.
В следующей таблице приведены правила сопоставления типов.
| Тип 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.
Сопоставление записей
Класс записи J можно преобразовать в CompositeType тогда и только тогда, когда все его компоненты можно преобразовать в открытые типы. В противном случае преобразование невозможно. Запись без компонентов преобразовать нельзя.
Сопоставление класса-записи с CompositeType
Запись, все компоненты которой можно преобразовать в открытые типы, также можно преобразовать в CompositeType. Класс-запись преобразуется в CompositeType следующим образом.
- Имя типа
CompositeTypeсовпадает с именем класса-записи. - Методами получения записи являются методы доступа к компонентам записи.
- Для каждого компонента записи типа T элемент в
CompositeTypeимеет то же имя, что и компонент записи, и тип opentype(T), согласно приведённым выше правилам сопоставления типов.
Сопоставление экземпляра класса-записи с CompositeData
Сопоставление экземпляра класса-записи с соответствующим CompositeType объектом CompositeData выполняется так же, как указано для других типов.
Восстановление экземпляра класса-записи из 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 должны быть зарегистрированы как MXBean на одном и том же сервере 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 и предпринимается попытка зарегистрировать его на том же сервере под другим именем, возникает исключение InstanceAlreadyExistsException. В целом не рекомендуется регистрировать один объект MBean под несколькими именами, в частности потому, что это плохо работает для MBean, являющихся 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, которое по историческим причинам отличается от соглашения для стандартных MBean. В интерфейсе стандартного 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 создаётся вызовом геттера для каждого элемента и его преобразованием в соответствующий тип Open Data. Таким образом, геттер, например
List<String> getNames()(илиList<String> names()для записи)
будет отображён в элемент с именем «names» и открытым типом ArrayType(1, SimpleType.STRING). При преобразовании в CompositeData будет вызван getNames(), а полученный List<String> будет преобразован в String[] для элемента «names».
CompositeData — это интерфейс. Конкретным классом, используемым для представления типа в виде Open Data, является CompositeDataSupport или другой класс, реализующий
CompositeData и сериализуемый как
CompositeDataSupport.
Восстановление экземпляра типа Java или класса-записи J из CompositeData
Если opendata(J) для типа Java J — это CompositeData, экземпляр J либо можно восстановить из CompositeData, либо J не подлежит восстановлению. Если какой-либо элемент в CompositeData не подлежит восстановлению, то и 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 завершается неудачей.Для любой возможной комбинации свойств должно выполняться одно из условий: (a) нет применимых конструкторов; (b) есть ровно один применимый конструктор; или (c) один из применимых конструкторов задаёт собственное надмножество свойств, указанных каждым из остальных применимых конструкторов. (Иными словами, выбор конструктора никогда не должен быть неоднозначным.) Если это условие не выполняется, 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, будет содержать все открытые конструкторы этого MXBean. Если класс MXBean не является открытым, его конструкторы также не считаются открытыми. Список, возвращаемый для MXBean, созданного с помощью класса StandardMBean, формируется так же, как и для Standard MBean. Независимо от способа создания MXBean, к его параметрам конструктора не применяются правила отображения MXBean, и им не соответствует OpenType.
Массив типов уведомлений, возвращаемый методом MBeanInfo.getNotifications() для MXBean, непосредственно зарегистрированного на сервере MBean, будет пустым, если MXBean не реализует интерфейс NotificationBroadcaster. В противном случае он будет содержать результат вызова NotificationBroadcaster.getNotificationInfo() на момент регистрации MXBean. Даже если впоследствии результат этого метода изменится, результат MBeanInfo.getNotifications() останется прежним. Список, возвращаемый для MXBean, созданного с помощью класса StandardMBean или StandardEmitterMBean, формируется так же, как и для Standard MBean.
В MBeanInfo объекте Descriptor для каждого из объектов MBeanAttributeInfo, MBeanParameterInfo и MBeanOperationInfo будет поле openType, значением которого будет OpenType, заданный приведёнными выше правилами отображения. Поэтому, даже если getType() имеет значение «int», getDescriptor().getField("openType") будет SimpleType.INTEGER.
В Descriptor каждого из этих объектов также будет поле originalType — строка, представляющая тип Java, используемый в интерфейсе MXBean. Формат этой строки описан ниже в разделе Имена типов.
В Descriptor для MBeanInfo будет поле mxbean со строковым значением «true».
Имена типов
Иногда немаппированный тип T параметра метода или возвращаемого значения в MXBean необходимо представить в виде строки. Если T — негenericный тип, этой строкой будет значение, возвращаемое методом Class.getName(). В противном случае это будет значение genericstring(T), определённое следующим образом:
- Если T — негenericный тип, не являющийся массивом, 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 в открытые типы обозначается исключением OpenDataException. Это может произойти при анализе интерфейса MXBean, например, если он ссылается на тип, такой как java.util.Random, у которого нет геттеров. Это также может произойти при преобразовании экземпляра (возвращаемого значения метода MXBean или параметра метода прокси MXBean), например при преобразовании SortedSet<String> в
String[], если у SortedSet есть ненулевой
Comparator.
Проблема при отображении в типы Java из открытых типов обозначается исключением InvalidObjectException. Это может произойти при анализе интерфейса MXBean, например, если он ссылается на тип, который согласно приведённым выше правилам не подлежит восстановлению, в контексте, где требуется восстанавливаемый тип. Это также может произойти при преобразовании экземпляра (параметра метода MXBean или возвращаемого значения метода прокси MXBean), например при преобразовании строки в перечисление, если не существует константы перечисления с таким именем.
В зависимости от контекста OpenDataException или InvalidObjectException может быть обёрнуто в другое исключение, например RuntimeMBeanException или UndeclaredThrowableException. Для каждого выброшенного исключения будет выполняться условие C: «e — это
OpenDataException или InvalidObjectException (в зависимости от ситуации) либо условие C выполняется для e.getCause()».
- Начиная с:
- 1.6
Краткое описание необязательных элементов
| Модификатор и тип | Необязательный элемент | Описание |
|---|---|---|
boolean |
value |
Значение true, если аннотированный интерфейс является интерфейсом MXBean. |
Подробное описание элементов
value
boolean value
- Возвращает:
- true, если аннотированный интерфейс является интерфейсом 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://docs.oracle.com/en/java/javase/25/docs/api/java.management/javax/management/MXBean.html