In the previous example, you had little control over the management interface of your bean; all of the public properties and methods of each exported bean was 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.
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 being exposed. The default implementation,
org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler
,
simply defines a management interface that exposes all public properties
and methods (as you saw in the previous examples). Spring provides two
additional implementations of the
MBeanInfoAssembler
interface that allow
you to control the generated management interface using either
source-level metadata or any arbitrary interface.
Using the MetadataMBeanInfoAssembler
you
can define the management interfaces for your beans using source level
metadata. The reading of metadata is encapsulated by the
org.springframework.jmx.export.metadata.JmxAttributeSource
interface. Out of the box, Spring JMX provides support for two
implementations of this interface:
org.springframework.jmx.export.metadata.AttributesJmxAttributeSource
for Commons Attributes and
org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource
for JDK 5.0 annotations. The
MetadataMBeanInfoAssembler
must be configured with an implementation instance
of the JmxAttributeSource
interface for it to
function correctly (there is no default). For the
following example, we will use the Commons Attributes metadata
approach.
To mark a bean for export to JMX, you should annotate the bean
class with the ManagedResource
attribute. In the
case of the Commons Attributes metadata approach this class can be found
in the org.springframework.jmx.metadata
package. Each
method you wish to expose as an operation must be marked with the
ManagedOperation
attribute and each property you
wish to expose must be marked with the
ManagedAttribute
attribute. 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.
The example below shows the JmxTestBean
class that you saw earlier marked with Commons Attributes
metadata:
package org.springframework.jmx; /** * @@org.springframework.jmx.export.metadata.ManagedResource * (description="My Managed Bean", objectName="spring:bean=test", * log=true, logFile="jmx.log", currencyTimeLimit=15, persistPolicy="OnUpdate", * persistPeriod=200, persistLocation="foo", persistName="bar") */ public class JmxTestBean implements IJmxTestBean { private String name; private int age; /** * @@org.springframework.jmx.export.metadata.ManagedAttribute * (description="The Age Attribute", currencyTimeLimit=15) */ public int getAge() { return age; } public void setAge(int age) { this.age = age; } /** * @@org.springframework.jmx.export.metadata.ManagedAttribute * (description="The Name Attribute", currencyTimeLimit=20, * defaultValue="bar", persistPolicy="OnUpdate") */ public void setName(String name) { this.name = name; } /** * @@org.springframework.jmx.export.metadata.ManagedAttribute * (defaultValue="foo", persistPeriod=300) */ public String getName() { return name; } /** * @@org.springframework.jmx.export.metadata.ManagedOperation * (description="Add Two Numbers Together") */ public int add(int x, int y) { return x + y; } public void dontExposeMe() { throw new RuntimeException(); } }
Here you can see that the JmxTestBean
class
is marked with the ManagedResource
attribute and
that this ManagedResource
attribute 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 section entitled Section 22.3.4, “Source-Level Metadata Types”.
You will also notice that both the age
and
name
properties are annotated with the
ManagedAttribute
attribute, but in the case of
the age
property, only the getter is marked. This
will cause both of these properties to be included in the management
interface as attributes, but the age
attribute will
be read-only.
Finally, you will notice that the add(int, int)
method is marked with the ManagedOperation
attribute whereas the dontExposeMe()
method is not.
This will cause the management interface to contain only one operation,
add(int, int)
, when using the
MetadataMBeanInfoAssembler
.
The code below shows how you configure the
MBeanExporter
to use the
MetadataMBeanInfoAssembler
:
<beans> <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"> <property name="beans"> <map> <entry key="bean:name=testBean1" value-ref="testBean"/> </map> </property> <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="attributeSource" class="org.springframework.jmx.export.metadata.AttributesJmxAttributeSource"> <property name="attributes"> <bean class="org.springframework.metadata.commons.CommonsAttributes"/> </property> </bean> <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"> <property name="attributeSource" ref="attributeSource"/> </bean> </beans>
Here you can see that an
MetadataMBeanInfoAssembler
bean has been
configured with an instance of the
AttributesJmxAttributeSource
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.
To enable the use of JDK 5.0 annotations for management interface
definition, Spring provides a set of annotations that mirror the Commons
Attribute attribute classes and an implementation of the
JmxAttributeSource
strategy interface,
the AnnotationsJmxAttributeSource
class, that
allows the MBeanInfoAssembler
to read
them.
The example below shows a bean where the management interface is defined by the presence of JDK 5.0 annotation types:
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(); } }
As you can see little has changed, other than the basic syntax of the metadata definitions.
<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>
The following source level metadata types are available for use in Spring JMX:
Table 22.2. Source-Level Metadata Types
Purpose | Commons Attributes Attribute | JDK 5.0 Annotation | Attribute / Annotation Type |
---|---|---|---|
Mark all instances of a Class as
JMX managed resources | ManagedResource | @ManagedResource | Class |
Mark a method as a JMX operation | ManagedOperation | @ManagedOperation | Method |
Mark a getter or setter as one half of a JMX attribute | ManagedAttribute | @ManagedAttribute | Method (only getters and setters) |
Define descriptions for operation parameters | ManagedOperationParameter | @ManagedOperationParameter and
@ManagedOperationParameters | Method |
The following configuration parameters are available for use on these source-level metadata types:
Table 22.3. Source-Level Metadata Parameters
Parameter | Description | Applies to |
---|---|---|
ObjectName | Used by MetadataNamingStrategy
to determine the ObjectName of a
managed resource | ManagedResource |
description | Sets the friendly description of the resource, attribute or operation | ManagedResource ,
ManagedAttribute ,
ManagedOperation ,
ManagedOperationParameter |
currencyTimeLimit | Sets the value of the
currencyTimeLimit descriptor field | ManagedResource ,
ManagedAttribute |
defaultValue | Sets the value of the defaultValue
descriptor field | ManagedAttribute |
log | Sets the value of the log descriptor
field | ManagedResource |
logFile | Sets the value of the logFile
descriptor field | ManagedResource |
persistPolicy | Sets the value of the persistPolicy
descriptor field | ManagedResource |
persistPeriod | Sets the value of the persistPeriod
descriptor field | ManagedResource |
persistLocation | Sets the value of the
persistLocation descriptor field | ManagedResource |
persistName | Sets the value of the persistName
descriptor field | ManagedResource |
name | Sets the display name of an operation parameter | ManagedOperationParameter |
index | Sets the index of an operation parameter | ManagedOperationParameter |
To simplify configuration even further, Spring introduces 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
then it is
allowed to "vote" on the inclusion of beans for exposure to JMX.
Out of the box, the only implementation of the
AutodetectCapableMBeanInfo
interface is the
MetadataMBeanInfoAssembler
which will vote to
include any bean which 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 like
this:
<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> <!-- (for Commons Attributes-based metadata) --> <bean id="attributeSource" class="org.springframework.jmx.export.metadata.AttributesJmxAttributeSource"> <property name="attributes"> <bean class="org.springframework.metadata.commons.CommonsAttributes"/> </property> </bean> <!-- (for Java 5+ annotations-based metadata) --> <!-- <bean id="attributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/> --> <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"> <property name="attributeSource" ref="attributeSource"/> </bean> </beans>
Notice that in this configuration no beans are passed to the
MBeanExporter
; however, the
JmxTestBean
will still be 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
Section 22.4, “Controlling the ObjectNames for your beans”.
In addition to the
MetadataMBeanInfoAssembler
, Spring also includes
the InterfaceBasedMBeanInfoAssembler
which allows
you to 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, the
InterfaceBasedMBeanInfoAssembler
extends this
functionality by removing the need for naming conventions, allowing you
to use more than one interface and removing the need for your beans to
implement the MBean interfaces.
Consider this interface that is used to define a management
interface for the JmxTestBean
class that you saw
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 will be exposed as operations and attributes on the JMX MBean. The code below 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>
Here you can see that 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 case above, 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 via 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, then the
InterfaceBasedMBeanInfoAssembler
will reflect on
the bean and use all of the interfaces implemented by that bean to
create the management interface.
The MethodNameBasedMBeanInfoAssembler
allows you to specify a list of method names that will be exposed to JMX
as attributes and operations. The code below shows a sample
configuration for this:
<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>
Here you can see that the methods add
and
myOperation
will be exposed as JMX operations and
getName()
, setName(String)
and
getAge()
will be exposed as the appropriate half of a
JMX attribute. In the code above, the method mappings apply to beans
that are exposed to JMX. To control method exposure on a bean-by-bean
basis, use the methodMappings
property of
MethodNameMBeanInfoAssembler
to map bean names to
lists of method names.