Controlling the Management Interface of Your Beans
In the example in the preceding section,
you had little control over the management interface of your bean. All of the public
properties and methods of each exported bean were exposed as JMX attributes and
operations, respectively. To exercise finer-grained control over exactly which
properties and methods of your exported beans are actually exposed as JMX attributes
and operations, Spring JMX provides a comprehensive and extensible mechanism for
controlling the management interfaces of your beans.
Using the MBeanInfoAssembler
Interface
Behind the scenes, the MBeanExporter
delegates to an implementation of the
org.springframework.jmx.export.assembler.MBeanInfoAssembler
interface, which is
responsible for defining the management interface of each bean that is exposed.
The default implementation,
org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler
,
defines a management interface that exposes all public properties and methods
(as you saw in the examples in the preceding sections). Spring provides two
additional implementations of the MBeanInfoAssembler
interface that let you
control the generated management interface by using either source-level metadata
or any arbitrary interface.
Using Source-level Metadata: Java Annotations
By using the MetadataMBeanInfoAssembler
, you can define the management interfaces
for your beans by using source-level metadata. The reading of metadata is encapsulated
by the org.springframework.jmx.export.metadata.JmxAttributeSource
interface.
Spring JMX provides a default implementation that uses Java annotations, namely
org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource
.
You must configure the MetadataMBeanInfoAssembler
with an implementation instance of
the JmxAttributeSource
interface for it to function correctly (there is no default).
To mark a bean for export to JMX, you should annotate the bean class with the
ManagedResource
annotation. You must mark each method you wish to expose as an operation
with the ManagedOperation
annotation and mark each property you wish to expose
with the ManagedAttribute
annotation. When marking properties, you can omit
either the annotation of the getter or the setter to create a write-only or read-only
attribute, respectively.
A ManagedResource -annotated bean must be public, as must the methods exposing
an operation or an attribute.
|
The following example shows the annotated version of the JmxTestBean
class that we
used in Creating an MBeanServer:
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();
}
}
In the preceding example, you can see that the JmxTestBean
class is marked with the
ManagedResource
annotation and that this ManagedResource
annotation is configured
with a set of properties. These properties can be used to configure various aspects
of the MBean that is generated by the MBeanExporter
and are explained in greater
detail later in Source-level Metadata Types.
Both the age
and name
properties are annotated with the ManagedAttribute
annotation, but, in the case of the age
property, only the getter is marked.
This causes both of these properties to be included in the management interface
as attributes, but the age
attribute is read-only.
Finally, the add(int, int)
method is marked with the ManagedOperation
attribute,
whereas the dontExposeMe()
method is not. This causes the management interface to
contain only one operation (add(int, int)
) when you use the MetadataMBeanInfoAssembler
.
The following configuration shows how you can configure the MBeanExporter
to use the
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"/>
<!-- will create management interface using annotation metadata -->
<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<!-- will pick up the ObjectName from the annotation -->
<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>
In the preceding example, an MetadataMBeanInfoAssembler
bean has been configured with an
instance of the AnnotationJmxAttributeSource
class and passed to the MBeanExporter
through the assembler property. This is all that is required to take advantage of
metadata-driven management interfaces for your Spring-exposed MBeans.
Source-level Metadata Types
The following table describes the source-level metadata types that are available for use in Spring JMX:
Purpose | Annotation | Annotation Type |
---|---|---|
Mark all instances of a |
|
Class |
Mark a method as a JMX operation. |
|
Method |
Mark a getter or setter as one half of a JMX attribute. |
|
Method (only getters and setters) |
Define descriptions for operation parameters. |
|
Method |
The following table describes the configuration parameters that are available for use on these source-level metadata types:
Parameter | Description | Applies to |
---|---|---|
|
Used by |
|
|
Sets the friendly description of the resource, attribute or operation. |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the value of the |
|
|
Sets the display name of an operation parameter. |
|
|
Sets the index of an operation parameter. |
|
Using the AutodetectCapableMBeanInfoAssembler
Interface
To simplify configuration even further, Spring includes the
AutodetectCapableMBeanInfoAssembler
interface, which extends the MBeanInfoAssembler
interface to add support for autodetection of MBean resources. If you configure the
MBeanExporter
with an instance of AutodetectCapableMBeanInfoAssembler
, it is
allowed to “vote” on the inclusion of beans for exposure to JMX.
The only implementation of the AutodetectCapableMBeanInfo
interface is
the MetadataMBeanInfoAssembler
, which votes to include any bean that is marked
with the ManagedResource
attribute. The default approach in this case is to use the
bean name as the ObjectName
, which results in a configuration similar to the following:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<!-- notice how no 'beans' are explicitly configured here -->
<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>
Notice that, in the preceding configuration, no beans are passed to the MBeanExporter
.
However, the JmxTestBean
is still registered, since it is marked with the ManagedResource
attribute and the MetadataMBeanInfoAssembler
detects this and votes to include it.
The only problem with this approach is that the name of the JmxTestBean
now has business
meaning. You can address this issue by changing the default behavior for ObjectName
creation as defined in Controlling ObjectName
Instances for Your Beans.
Defining Management Interfaces by Using Java Interfaces
In addition to the MetadataMBeanInfoAssembler
, Spring also includes the
InterfaceBasedMBeanInfoAssembler
, which lets you constrain the methods and
properties that are exposed based on the set of methods defined in a collection of
interfaces.
Although the standard mechanism for exposing MBeans is to use interfaces and a simple
naming scheme, InterfaceBasedMBeanInfoAssembler
extends this functionality by
removing the need for naming conventions, letting you use more than one interface
and removing the need for your beans to implement the MBean interfaces.
Consider the following interface, which is used to define a management interface for the
JmxTestBean
class that we showed earlier:
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();
}
This interface defines the methods and properties that are exposed as operations and attributes on the JMX MBean. The following code shows how to configure Spring JMX to use this interface as the definition for the management interface:
<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>
In the preceding example, the InterfaceBasedMBeanInfoAssembler
is configured to use the
IJmxTestBean
interface when constructing the management interface for any bean. It is
important to understand that beans processed by the InterfaceBasedMBeanInfoAssembler
are not required to implement the interface used to generate the JMX management
interface.
In the preceding case, the IJmxTestBean
interface is used to construct all management
interfaces for all beans. In many cases, this is not the desired behavior, and you may
want to use different interfaces for different beans. In this case, you can pass
InterfaceBasedMBeanInfoAssembler
a Properties
instance through the interfaceMappings
property, where the key of each entry is the bean name and the value of each entry is a
comma-separated list of interface names to use for that bean.
If no management interface is specified through either the managedInterfaces
or
interfaceMappings
properties, the InterfaceBasedMBeanInfoAssembler
reflects
on the bean and uses all of the interfaces implemented by that bean to create the
management interface.
Using MethodNameBasedMBeanInfoAssembler
MethodNameBasedMBeanInfoAssembler
lets you specify a list of method names
that are exposed to JMX as attributes and operations. The following code shows a sample
configuration:
<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>
In the preceding example, you can see that the add
and myOperation
methods are exposed as JMX
operations, and getName()
, setName(String)
, and getAge()
are exposed as the
appropriate half of a JMX attribute. In the preceding code, the method mappings apply to
beans that are exposed to JMX. To control method exposure on a bean-by-bean basis, you can use
the methodMappings
property of MethodNameMBeanInfoAssembler
to map bean names to
lists of method names.