Аннотация Интерфейс 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.
Концепции легче понять при сравнении со стандартной концепцией MBean. Вот как управляемый объект может быть представлен как Standard MBean и как MXBean:
Standard MBean
public interface MemoryPoolMBean {
String getName();
MemoryUsage getUsage();
// ...
}
MXBean
public interface MemoryPoolMXBean {
String getName();
MemoryUsage getUsage();
// ...
}
Как вы можете видеть, определения очень похожи. Единственное отличие заключается в том, что соглашение об именовании интерфейса для MXBean использует SomethingMXBean вместо SomethingMBean для Standard MBeans.
В этом управляемом объекте есть атрибут, называемый 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 MBeans клиент MBean Server не может получить доступ к атрибуту Usage, если не знает класс MemoryUsage. Предположим, что клиент — это обобщённая консоль, основанная на технологии JMX. В таком случае консоль должна быть настроена с модель-специфичными классами каждого приложения, к которому она может подключиться. Проблема ещё больше усугубляется для клиентов, написанных не на языке Java. Тогда может не быть никакого способа рассказать клиенту, как выглядит MemoryUsage.
Вот где MXBeans отличаются от Standard MBeans. Хотя мы определяем интерфейс управления почти точно так же, как и раньше, фреймворк 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 должны быть восстанавливаемыми.
Значения null допускаются для всех типов Java и типов Открытых типов, за исключением примитивных типов 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
Сопоставление экземпляра класса записи с 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.ConstructoProperties, то один из этих конструкторов (не обязательно всегда один и тот же) будет вызван для реконструкции экземпляра 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 MBeans. Независимо от того, как была построена MXBean, параметры её конструкторов не подчиняются правилам сопоставления MXBean и не имеют соответствующего OpenType.
Массив типов уведомлений, возвращаемых методом MBeanInfo.getNotifications() для MXBean, зарегистрированной непосредственно в MBean Server, будет пустым, если MXBean не реализует интерфейс NotificationBroadcaster. В противном случае, это результат вызова NotificationBroadcaster.getNotificationInfo() в момент регистрации MXBean. Даже если результат этого метода меняется впоследствии, результат MBeanInfo.getNotifications() не изменится. Список, возвращаемый для MXBean, созданной с помощью класса StandardMBean или StandardEmitterMBean, выводится аналогично Standard MBeans.
Описание 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
- Returns:
- true, если аннотированный интерфейс является интерфейсом MXBean.
- Default:
- true
© 1993, 2021, 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/17/docs/api/java.management/javax/management/MXBean.html