В примере из предыдущего раздела контроль над интерфейсом управления бина осуществлялся в малой степени. Все публичные свойства и методы каждого экспортируемого бина были открыты как атрибуты и операции JMX, соответственно. Для осуществления более тонкого контроля над тем, какие именно свойства и методы экспортируемых вами бинов на самом деле открыты как атрибуты и операции JMX, средства поддержки Spring для JMX предусматривают комплексный и расширяемый механизм контроля над интерфейсами управления бинами.

Использование интерфейса MBeanInfoAssembler

"За кулисами" MBeanExporter делегирует свои полномочия реализации интерфейса org.springframework.jmx.export.assembler.MBeanInfoAssembler, который отвечает за определение интерфейса управления каждого экспортируемого бина. Реализация по умолчанию, org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler, определяет интерфейс управления, который открывает все публичные свойства и методы (как видно из примеров в предыдущих разделах). Spring предоставляет две дополнительные реализации интерфейса MBeanInfoAssembler, которые позволяют контролировать сгенерированный интерфейс управления, используя либо метаданные на уровне источника, либо произвольный интерфейс.

Использование метаданных на уровне источника: Java-аннотации

Используя MetadataMBeanInfoAssembler, можно определять интерфейсы управления для ваших бинов, используя метаданные на уровне источника. Чтение метаданных инкапсулируется интерфейсом org.springframework.jmx.export.metadata.JmxAttributeSource. Фреймворк JMX в Spring предусматривает реализацию по умолчанию, которая использует Java-аннотации, а именно org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource. Для корректной работы MetadataMBeanInfoAssembler необходимо сконфигурировать экземпляр реализации интерфейса JmxAttributeSource (по умолчанию он отсутствует).

Чтобы пометить бин для экспорта в JMX, необходимо аннотировать класс бина аннотацией ManagedResource. Нужно помечать каждый метод, который необходимо открыть как операцию, аннотацией ManagedOperation, а также помечать ManagedAttribute каждое свойство, которое необходимо открыть. Помечая свойства, можно опустить аннотацию геттера или сеттера, чтобы создать атрибут "только для записи" или "только для чтения", соответственно.

Помеченный аннотацией ManagedResource бин должен быть публичным, как и методы, открывающие операцию или атрибут.

В следующем примере показана аннотированная версия класса JmxTestBean:

package org.springframework.jmx;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedAttribute;
@ManagedResource(
        objectName="bean:name=testBean4",
        description="My Managed Bean",
        log=true,
        logFile="jmx.log",
        currencyTimeLimit=15,
        persistPolicy="OnUpdate",
        persistPeriod=200,
        persistLocation="foo",
        persistName="bar")
public class AnnotationTestBean implements IJmxTestBean {
    private String name;
    private int age;
    @ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15)
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @ManagedAttribute(description="The Name Attribute",
            currencyTimeLimit=20,
            defaultValue="bar",
            persistPolicy="OnUpdate")
    public void setName(String name) {
        this.name = name;
    }
    @ManagedAttribute(defaultValue="foo", persistPeriod=300)
    public String getName() {
        return name;
    }
    @ManagedOperation(description="Add two numbers")
    @ManagedOperationParameters({
        @ManagedOperationParameter(name = "x", description = "The first number"),
        @ManagedOperationParameter(name = "y", description = "The second number")})
    public int add(int x, int y) {
        return x + y;
    }
    public void dontExposeMe() {
        throw new RuntimeException();
    }
}

Из предыдущего примера видно, что класс JmxTestBean помечен аннотацией ManagedResource и что эта аннотация ManagedResource сконфигурирована с набором свойств. Эти свойства могут быть использованы для настройки различных аспектов MBean, который генерируется MBeanExporter, и более подробно описаны далее.

Оба свойства – age и name – помечены аннотацией ManagedAttribute, но в случае свойства age помечен только геттер. В результате оба эти свойства будут включены в интерфейс управления как атрибуты, но атрибут age будет доступен только для чтения.

Наконец, метод add(int, int) помечен атрибутом ManagedOperation, а метод dontExposeMe() – нет. Это приводит к тому, что интерфейс управления содержит только одну операцию (add(int, int)) при использовании MetadataMBeanInfoAssembler.

Следующая конфигурация показывает, как можно настроить MBeanExporter на использование MetadataMBeanInfoAssembler:

<beans>
    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
        <property name="assembler" ref="assembler"/>
        <property name="namingStrategy" ref="namingStrategy"/>
        <property name="autodetect" value="true"/>
    </bean>
    <bean id="jmxAttributeSource"
            class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
    <!-- создаст интерфейс управления, используя метаданные аннотации -->
    <bean id="assembler"
            class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
        <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
    <!-- перехватит имя объекта из аннотации -->
    <bean id="namingStrategy"
            class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
        <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
    <bean id="testBean" class="org.springframework.jmx.AnnotationTestBean">
        <property name="name" value="TEST"/>
        <property name="age" value="100"/>
    </bean>
</beans>

В предыдущем примере бин MetadataMBeanInfoAssembler был сконфигурирован с экземпляром класса AnnotationJmxAttributeSource и передан MBeanExporter через свойство ассемблера. Это все, что требуется для использования преимуществ интерфейсов управления на основе метаданных для ваших бинов MBean, переданных в Spring.

Типы метаданных на уровне источника

В следующей таблице описаны типы метаданных на уровне источника, которые доступны для использования в JMX через Spring:

Таблица 7. Типы метаданных на уровне источника
Назначение @annotation: Тип аннотации

Помечает все экземпляры Class как управляемые JMX-ресурсы.

@ManagedResource

Класс

Помечает метод как JMX-операцию.

@ManagedOperation

Метод

Помечает геттер или сеттер как одну половину JMX-атрибута.

@ManagedAttribute

Метод (только геттеры и сеттеры)

Определяет описания для параметров операции.

@ManagedOperationParameter и @ManagedOperationParameters

Метод

В следующей таблице описаны параметры конфигурации, доступные для использования в этих типах метаданных на уровне источника:

Таблица 8. Параметры метаданных на уровне источника
Параметр Описание Применимо к

ObjectName

Используется MetadataNamingStrategy для определения ObjectName управляемого ресурса.

ManagedResource

description

Устанавливает удобное для использования описание ресурса, атрибута или операции.

ManagedResource, ManagedAttribute, ManagedOperation, или ManagedOperationParameter

currencyTimeLimit

Устанавливает значение поля дескриптора currencyTimeLimit.

ManagedResource или ManagedAttribute

defaultValue

Устанавливает значение поля дескриптора defaultValue.

ManagedAttribute

log

Устанавливает значение поля дескриптора log.

ManagedResource

logFile

Устанавливает значение поля дескриптора logFile.

ManagedResource

persistPolicy

Устанавливает значение поля дескриптора persistPolicy.

ManagedResource

persistPeriod

Устанавливает значение поля дескриптора persistPeriod.

ManagedResource

persistLocation

Устанавливает значение поля дескриптора persistLocation.

ManagedResource

persistName

Устанавливает значение поля дескриптора persistName.

ManagedResource

name

Устанавливает отображаемое имя параметра операции.

ManagedOperationParameter

index

Устанавливает индекс параметра операции.

ManagedOperationParameter

Использование интерфейса AutodetectCapableMBeanInfoAssembler

Чтобы еще больше упростить конфигурирование, Spring предусматривает интерфейс AutodetectCapableMBeanInfoAssembler, который расширяет интерфейс MBeanInfoAssembler для добавления средств поддержки автоматического определения MBean-ресурсов. Если сконфигурировать MBeanExporter с экземпляром AutodetectCapableMBeanInfoAssembler, ему будет разрешено "голосовать" за то, чтобы бины были включены в список для открытия в JMX.

Единственной реализацией интерфейса AutodetectCapableMBeanInfo является MetadataMBeanInfoAssembler, который голосует за включение любого бина, помеченного атрибутом ManagedResource. По умолчанию в этом случае в качестве ObjectName используется имя бина, что приводит нас к конфигурации, подобной следующей:

<beans>
    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
        <!-- обратите внимание, что здесь нет явной конфигурации "бинов" -->
        <property name="autodetect" value="true"/>
        <property name="assembler" ref="assembler"/>
    </bean>
    <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
        <property name="name" value="TEST"/>
        <property name="age" value="100"/>
    </bean>
    <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
        <property name="attributeSource">
            <bean class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
        </property>
    </bean>
</beans>

Обратите внимание, что в предыдущей конфигурации MBeanExporter никакие бины не передаются. Однако JmxTestBean все еще зарегистрирован, поскольку он помечен атрибутом ManagedResource, это обнаруживает MetadataMBeanInfoAssembler и голосует за включение этого бина. Единственная проблема данного подхода заключается в том, что имя JmxTestBean теперь имеет бизнес-значение. Эту проблему можно решить, изменив логику поведения по умолчанию для создания ObjectName.

Определение интерфейсов управления с помощью интерфейсов Javas

В дополнение к MetadataMBeanInfoAssembler, Spring также содержит InterfaceBasedMBeanInfoAssembler, который позволяет ограничивать методы и свойства, которые открыты на основе набора методов, определенных в коллекции интерфейсов.

Хотя стандартным механизмом для открытия MBeans является использование интерфейсов и простой схемы назначения имен, InterfaceBasedMBeanInfoAssembler расширяет эту функциональность, устраняя необходимость в соглашениях об именовании, позволяя использовать более одного интерфейса и устраняя необходимость для бинов реализовывать MBean-интерфейсы.

Рассмотрим следующий интерфейс, который используется для определения интерфейса управления для класса JmxTestBean, который мы показали ранее:

public interface IJmxTestBean {
    public int add(int x, int y);
    public long myOperation();
    public int getAge();
    public void setAge(int age);
    public void setName(String name);
    public String getName();
}

Этот интерфейс определяет методы и свойства, открытые в качестве операций и атрибутов JMX MBean. Следующий код показывает, как сконфигурировать JMX в Spring на использование этого интерфейса в качестве определения для интерфейса управления:

<beans>
    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
        <property name="beans">
            <map>
                <entry key="bean:name=testBean5" value-ref="testBean"/>
            </map>
        </property>
        <property name="assembler">
            <bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
                <property name="managedInterfaces">
                    <value>org.springframework.jmx.IJmxTestBean</value>
                </property>
            </bean>
        </property>
    </bean>
    <bean id="testBean" class="org.springframework.jmx.JmxTestBean">
        <property name="name" value="TEST"/>
        <property name="age" value="100"/>
    </bean>
</beans>

В предыдущем примере InterfaceBasedMBeanInfoAssembler сконфигурирован на использование интерфейса IJmxTestBean при построении интерфейса управления для любого бина. Важно понимать, что бины, обрабатываемые InterfaceBasedMBeanInfoAssembler, не обязательно должны реализовывать интерфейс, используемый для генерации интерфейса управления JMX.

В предыдущем случае интерфейс IJmxTestBean используется для построения всех интерфейсов управления для всех бинов. Во многих случаях такая логика работы не является желаемой, поэтому может возникнуть желание использовать разные интерфейсы для разных бинов. В этом случае можно передать интерфейсу InterfaceBasedMBeanInfoAssembler экземпляр Properties через свойство interfaceMappings, где ключом каждой записи является имя бина, а значением каждой записи – разделенный запятыми список имен интерфейсов, которые следует использовать для этого бина.

Если интерфейс управления не задан через свойства managedInterfaces или interfaceMappings, интерфейс InterfaceBasedMBeanInfoAssembler отражает бин и использует все интерфейсы, реализованные этим бином, для создания интерфейса управления.

Использование MethodNameBasedMBeanInfoAssembler

MethodNameBasedMBeanInfoAssembler позволяет задать список имен методов, которые открыты для JMX как атрибуты и операции. В следующем коде показан пример конфигурации:

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
        <map>
            <entry key="bean:name=testBean5" value-ref="testBean"/>
        </map>
    </property>
    <property name="assembler">
        <bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
            <property name="managedMethods">
                <value>add,myOperation,getName,setName,getAge</value>
            </property>
        </bean>
    </property>
</bean>

Из предыдущего примера понятно, что методы add и myOperation открыты как JMX-операции, а getName(), setName(String) и getAge() открыты как соответствующие половины JMX-атрибутов. В предыдущем коде отображения методов применяются к бинам, которые открыты для JMX. Чтобы управлять воздействием методов на каждый бин, можно использовать methodMappings свойства MethodNameMBeanInfoAssembler для отображения имен бинов на списки имен методов.