Интерфейс аннотаций MXBean
@Documented @Retention(RUNTIME) @Target(TYPE) public @interface MXBean
Аннотация для явного обозначения интерфейса как интерфейса 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.
Концепции легче понять по сравнению с концепцией 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. Хотя мы определяем интерфейс управления почти точно так же, как и 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 MBeans или MXBeans:
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 MBeans и MXBeans.
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 и открытый тип атрибута определяются правилами сопоставления ниже. Методfinal Class getClass()унаследованный отObjectигнорируется при поиске геттеров. - Метод
boolean isN()указывает, что существует читаемый атрибут, называемыйNс типом Javabooleanи открытым типомSimpleType.Boolean. - Метод
void setN(T x)указывает, что существует записываемый атрибут, называемыйN. Тип Java и открытый тип атрибута определяются правилами сопоставления ниже. (Конечно, имяxпараметра не имеет значения.) - Все остальные методы указывают на то, что существует операция с тем же именем, что и метод. Тип Java и открытый тип возвращаемого значения и каждого параметра определяются правилами сопоставления ниже.
Правила для getN и isN вместе определяют понятие геттера. Правило для setN определяет понятие сеттера.
Ошибка, если существуют два геттера с одинаковым именем или два сеттера с одинаковым именем. Если есть геттер и сеттер с одинаковым именем, то тип T в обоих случаях должен быть одинаковым. В этом случае атрибут является читаемым и записываемым. Если есть только геттер или только сеттер, атрибут является только для чтения или только для записи соответственно.
Правила сопоставления типов
MXBean — это вид Open MBean, как определено в пакете javax.management.openmbean. Это означает, что типы атрибутов, параметров операций и возвращаемых значений операций должны быть описаны с использованием открытых типов, то есть четырёх стандартных подклассов OpenType. MXBeans достигают этого, сопоставляя типы 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 и Открытых типов, за исключением примитивных типов 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.
Сопоставления для записей
Класс-запись 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 должны быть зарегистрированы как 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, и попытка зарегистрировать его в том же сервере 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, которое по историческим причинам отличается от соглашения 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" и открытым типом ArrayType(1, SimpleType.STRING). Преобразование в 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 терпит неудачу.Для любой возможной комбинации свойств должно выполняться одно из следующих условий: (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, выводится аналогичным образом, как и для стандартных MBean.
Независимо от способа создания MXBean, его параметры конструктора не подлежат правилам отображения MXBean и не имеют соответствующего OpenType.
Массив типов уведомлений, возвращаемых методом MBeanInfo.getNotifications() для MXBean, зарегистрированного непосредственно в сервере MBean, будет пустым, если MXBean не реализует интерфейс NotificationBroadcaster. В противном случае это будет результат вызова метода NotificationBroadcaster.getNotificationInfo() в момент регистрации MXBean. Даже если результат этого метода впоследствии изменится, результат MBeanInfo.getNotifications() не изменится. Список, возвращаемый для MXBean, созданного с использованием класса StandardMBean или StandardEmitterMBean, выводится аналогичным образом, как и для стандартных 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), например, из строки в перечисление, если нет константы перечисления с этим именем.
В зависимости от контекста OpenDataException или InvalidObjectException могут быть обернуты в другое исключение, такое как RuntimeMBeanException или UndeclaredThrowableException. Для каждого сгенерированного исключения условие C будет истинным: «e является
OpenDataException или InvalidObjectException (как соответствующим образом), или C истинно для e.getCause()».
- Since:
- 1.6
Краткое описание необязательных элементов
| Модификатор и тип | Необязательный элемент | Описание |
|---|---|---|
boolean |
value |
Истинно, если аннотированный интерфейс является интерфейсом MXBean. |
Подробное описание элементов
value
boolean value
- Возвращает:
- истинно, если аннотированный интерфейс является интерфейсом MXBean.
- По умолчанию:
true
© 1993, 2023, 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/21/docs/api/java.management/javax/management/MXBean.html