JMX Support
Spring Integration provides channel Adapters for receiving and publishing JMX Notifications.
You need to include this dependency into your project:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
compile "org.springframework.integration:spring-integration-jmx:5.3.3.RELEASE"
An inbound channel adapter allows for polling JMX MBean attribute values, and an outbound channel adapter allows for invoking JMX MBean operations.
Notification-listening Channel Adapter
The notification-listening channel adapter requires a JMX ObjectName
for the MBean that publishes notifications to which this listener should be registered.
A very simple configuration might resemble the following:
<int-jmx:notification-listening-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"/>
The notification-listening-channel-adapter registers with an MBeanServer at startup, and the default bean name is mbeanServer , which happens to be the same bean name generated when using Spring’s <context:mbean-server/> element.
If you need to use a different name, be sure to include the mbean-server attribute.
|
The adapter can also accept a reference to a NotificationFilter
and a “handback” object to provide some context that is passed back with each notification.
Both of those attributes are optional.
Extending the preceding example to include those attributes as well as an explicit MBeanServer
bean name produces the following example:
<int-jmx:notification-listening-channel-adapter id="adapter"
channel="channel"
mbean-server="someServer"
object-name="example.domain:name=somePublisher"
notification-filter="notificationFilter"
handback="myHandback"/>
The _Notification-listening channel adapter is event-driven and registered with the MBeanServer
directly.
It does not require any poller configuration.
For this component only, the
The names of the located MBean(s) are logged when DEBUG level logging is enabled. |
Notification-publishing Channel Adapter
The notification-publishing channel adapter is relatively simple. It requires only a JMX object name in its configuration, as the following example shows:
<context:mbean-export/>
<int-jmx:notification-publishing-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"/>
It also requires that an MBeanExporter
be present in the context.
That is why the <context:mbean-export/>
element is also shown in the preceding example.
When messages are sent to the channel for this adapter, the notification is created from the message content.
If the payload is a String
, it is passed as the message
text for the notification.
Any other payload type is passed as the userData
of the notification.
JMX notifications also have a type
, and it should be a dot-delimited String
.
There are two ways to provide the type
.
Precedence is always given to a message header value associated with the JmxHeaders.NOTIFICATION_TYPE
key.
Alternatively, you can provide a fallback default-notification-type
attribute in the configuration, as the following example shows:
<context:mbean-export/>
<int-jmx:notification-publishing-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=publisher"
default-notification-type="some.default.type"/>
Attribute-polling Channel Adapter
The attribute-polling channel adapter is useful when you need to periodically check on some value that is available through an MBean as a managed attribute.
You can configured the poller in the same way as any other polling adapter in Spring Integration (or you can rely on the default poller).
The object-name
and the attribute-name
are required.
An MBeanServer reference is also required.
However, by default, it automatically checks for a bean named mbeanServer
, same as the notification-listening channel adapter described earlier.
The following example shows how to configure an attribute-polling channel adapter with XML:
<int-jmx:attribute-polling-channel-adapter id="adapter"
channel="channel"
object-name="example.domain:name=someService"
attribute-name="InvocationCount">
<int:poller max-messages-per-poll="1" fixed-rate="5000"/>
</int-jmx:attribute-polling-channel-adapter>
Tree-polling Channel Adapter
The tree-polling channel adapter queries the JMX MBean tree and sends a message with a payload that is the graph of objects that matches the query.
By default, the MBeans are mapped to primitives and simple objects, such as Map
, List
, and arrays.
Doing so permits simple transformation to (for example) JSON.
An MBeanServer reference is also required.
However, by default, it automatically checks for a bean named mbeanServer
, same as the notification-listening channel adapter described earlier.
The following example shows how to configure an tree-polling channel adapter with XML:
<int-jmx:tree-polling-channel-adapter id="adapter"
channel="channel"
query-name="example.domain:type=*">
<int:poller max-messages-per-poll="1" fixed-rate="5000"/>
</int-jmx:tree-polling-channel-adapter>
The preceding example includes all of the attributes on the selected MBeans.
You can filter the attributes by providing an MBeanObjectConverter
that has an appropriate filter configured.
You can provide the converter as a reference to a bean definition by using the converter
attribute, or you can use an inner <bean/>
definition.
Spring Integration provides a DefaultMBeanObjectConverter
that can take a MBeanAttributeFilter
in its constructor argument.
Spring Integration provides two standard filters.
The NamedFieldsMBeanAttributeFilter
lets you specify a list of attributes to include.
The NotNamedFieldsMBeanAttributeFilter
lets you specify a list of attributes to exclude.
You can also implement your own filter.
Operation-invoking Channel Adapter
The operation-invoking channel adapter enables message-driven invocation of any managed operation exposed by an MBean.
Each invocation requires the operation name to be invoked and the object name of the target MBean.
Both of these must be explicitly provided by adapter configuration or via JmxHeaders.OBJECT_NAME
and JmxHeaders.OPERATION_NAME
message headers, respectively:
<int-jmx:operation-invoking-channel-adapter id="adapter"
object-name="example.domain:name=TestBean"
operation-name="ping"/>
Then the adapter only needs to be able to discover the mbeanServer
bean.
If a different bean name is required, then provide the mbean-server
attribute with a reference.
The payload of the message is mapped to the parameters of the operation, if any.
A Map
-typed payload with String
keys is treated as name/value pairs, whereas a List
or array is passed as a simple argument list (with no explicit parameter names).
If the operation requires a single parameter value, the payload can represent that single value.
Also, if the operation requires no parameters, the payload would be ignored.
If you want to expose a channel for a single common operation to be invoked by messages that need not contain headers, that last option works well.
Operation-invoking Outbound Gateway
Similarly to the operation-invoking channel adapter, Spring Integration also provides an operation-invoking outbound gateway, which you can use when dealing with non-void operations when a return value is required.
The return value is sent as the message payload to the reply-channel
specified by the gateway.
The following example shows how to configure an operation-invoking outbound gateway with XML:
<int-jmx:operation-invoking-outbound-gateway request-channel="requestChannel"
reply-channel="replyChannel"
object-name="o.s.i.jmx.config:type=TestBean,name=testBeanGateway"
operation-name="testWithReturn"/>
If you do not provide the reply-channel
attribute, the reply message is sent to the channel identified by the IntegrationMessageHeaderAccessor.REPLY_CHANNEL
header.
That header is typically auto-created by the entry point into a message flow, such as any gateway component.
However, if the message flow was started by manually creating a Spring Integration message and sending it directly to a channel, you must specify the message header explicitly or use the reply-channel
attribute.
MBean Exporter
Spring Integration components may themselves be exposed as MBeans when the IntegrationMBeanExporter
is configured.
To create an instance of the IntegrationMBeanExporter
, define a bean and provide a reference to an MBeanServer
and a domain name (if desired).
You can leave out the domain, in which case the default domain is org.springframework.integration
.
The following example shows how to declare an instance of an IntegrationMBeanExporter
and an associated MBeanServer
instance:
<int-jmx:mbean-export id="integrationMBeanExporter"
default-domain="my.company.domain" server="mbeanServer"/>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true"/>
</bean>
The MBean exporter is orthogonal to the one provided in Spring core.
It registers message channels and message handlers but does not register itself.
You can expose the exporter itself (and certain other components in Spring Integration) by using the standard It also has a useful operation, as discussed in Orderly Shutdown Managed Operation. |
Spring Integration 4.0 introduced the @EnableIntegrationMBeanExport
annotation to allow for convenient configuration of a default integrationMbeanExporter
bean of type IntegrationMBeanExporter
with several useful options at the @Configuration
class level.
The following example shows how to configure this bean:
@Configuration
@EnableIntegration
@EnableIntegrationMBeanExport(server = "mbeanServer", managedComponents = "input")
public class ContextConfiguration {
@Bean
public MBeanServerFactoryBean mbeanServer() {
return new MBeanServerFactoryBean();
}
}
If you need to provide more options or have several IntegrationMBeanExporter
beans (such as
for different MBean Servers or to avoid conflicts with the standard Spring MBeanExporter
— such as through
@EnableMBeanExport
), you can configure an IntegrationMBeanExporter
as a generic bean.
MBean Object Names
All the MessageChannel
, MessageHandler
, and MessageSource
instances in the application are wrapped by the MBean exporter to provide management and monitoring features.
The generated JMX object names for each component type are listed in the following table:
Component Type | Object Name |
---|---|
MessageChannel |
`o.s.i:type=MessageChannel,name=<channelName>` |
MessageSource |
`o.s.i:type=MessageSource,name=<channelName>,bean=<source>` |
MessageHandler |
`o.s.i:type=MessageSource,name=<channelName>,bean=<source>` |
The bean
attribute in the object names for sources and handlers takes one of the values in the following table:
Bean Value | Description |
---|---|
endpoint |
The bean name of the enclosing endpoint (for example |
anonymous |
An indication that the enclosing endpoint did not have a user-specified bean name, so the JMX name is the input channel name. |
internal |
For well known Spring Integration default components |
handler/source |
None of the above.
Fall back to the |
You can append custom elements to the object name by providing a reference to a Properties
object in the object-name-static-properties
attribute.
Also, since Spring Integration 3.0, you can use a custom ObjectNamingStrategy
by setting the object-naming-strategy
attribute.
Doing so permits greater control over the naming of the MBeans, such as grouping all integration MBeans under an 'Integration' type.
The following example shows one possible custom naming strategy implementation:
public class Namer implements ObjectNamingStrategy {
private final ObjectNamingStrategy realNamer = new KeyNamingStrategy();
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
String actualBeanKey = beanKey.replace("type=", "type=Integration,componentType=");
return realNamer.getObjectName(managedBean, actualBeanKey);
}
}
The beanKey
argument is a String
that contain the standard object name, beginning with the default-domain
and including any additional static properties.
The preceding example moves the standard type
part to componentType
and sets the type
to 'Integration', enabling selection of all Integration MBeans in one query:`my.domain:type=Integration,*`.
Doing so also groups the beans under one tree entry under the domain in such tools as VisualVM.
The default naming strategy is a MetadataNamingStrategy .
The exporter propagates the default-domain to that object to let it generate a fallback object name if parsing of the bean key fails.
If your custom naming strategy is a MetadataNamingStrategy (or a subclass of it), the exporter does not propagate the default-domain .
You must configure it on your strategy bean.
|
Starting with version 5.1; any bean names (represented by the name
key in the object name) will be quoted if they contain any characters that are not allowed in a Java identifier (or period .
).
JMX Improvements
Version 4.2 introduced some important improvements, representing a fairly major overhaul to the JMX support in the framework. These resulted in a significant performance improvement of the JMX statistics collection and much more control thereof. However, it has some implications for user code in a few specific (uncommon) situations. These changes are detailed below, with a caution where necessary.
- Metrics Capture
-
Previously,
MessageSource
,MessageChannel
, andMessageHandler
metrics were captured by wrapping the object in a JDK dynamic proxy to intercept appropriate method calls and capture the statistics. The proxy was added when an integration MBean exporter was declared in the context.Now, the statistics are captured by the beans themselves. See Metrics and Management for more information.
This change means that you no longer automatically get an MBean or statistics for custom MessageHandler
implementations, unless those custom handlers extendAbstractMessageHandler
. The simplest way to resolve this is to extendAbstractMessageHandler
. If you cannot do so, another work around is to implement theMessageHandlerMetrics
interface. For convenience, aDefaultMessageHandlerMetrics
is provided to capture and report statistics. You should invoke thebeforeHandle
andafterHandle
at the appropriate times. YourMessageHandlerMetrics
methods can then delegate to this object to obtain each statistic. Similarly,MessageSource
implementations must extendAbstractMessageSource
or implementMessageSourceMetrics
. Message sources capture only a count, so there is no provided convenience class. You should maintain the count in anAtomicLong
field.The removal of the proxy has two additional benefits:
-
Stack traces in exceptions are reduced (when JMX is enabled) because the proxy is not on the stack
-
Cases where two MBeans were exported for the same bean now only export a single MBean with consolidated attributes and operations (see the MBean consolidation bullet, later).
-
- Resolution
-
System.nanoTime()
(rather thanSystem.currentTimeMillis()
) is now used to capture times . This may provide more accuracy on some JVMs, espcially when you expect durations of less than one millisecond. - Setting Initial Statistics Collection State
-
Previously, when JMX was enabled, all sources, channels, and handlers captured statistics. You can now control whether the statistics are enabled on an individual component. Further, you can capture simple counts on
MessageChannel
instances andMessageHandler
instances instead of capturing the complete time-based statistics. This can have significant performance implications, because you can selectively configure where you need detailed statistics and enable and disable collection at runtime. - @IntegrationManagedResource
-
Similar to the
@ManagedResource
annotation, the@IntegrationManagedResource
marks a class as being eligible to be exported as an MBean. However, it is exported only if the application context has anIntegrationMBeanExporter
.Certain Spring Integration classes (in the
org.springframework.integration
) package) that were previously annotated with`@ManagedResource` are now annotated with both@ManagedResource
and@IntegrationManagedResource
. This is for backwards compatibility (see the next item). Such MBeans are exported by any contextMBeanServer
or by anIntegrationMBeanExporter
(but not both — if both exporters are present, the bean is exported by the integration exporter if the bean matches amanaged-components
pattern). - Consolidated MBeans
-
Certain classes within the framework (mapping routers, for example) have additional attributes and operations over and above those provided by metrics and
Lifecycle
. We use aRouter
as an example here.Previously, beans of these types were exported as two distinct MBeans:
-
The metrics MBean (with an object name such as
intDomain:type=MessageHandler,name=myRouter,bean=endpoint
). This MBean had metrics attributes and metrics/Lifecycle operations. -
A second MBean (with an object name such as
ctxDomain:name=org.springframework.integration.config.
RouterFactoryBean#0
,type=MethodInvokingRouter`) was exported with the channel mappings attribute and operations.Now the attributes and operations are consolidated into a single MBean. The object name depends on the exporter. If exported by the integration MBean exporter, the object name is, for example:
intDomain:type=MessageHandler,name=myRouter,bean=endpoint
. If exported by another exporter, the object name is, for example:ctxDomain:name=org.springframework.integration.config.
RouterFactoryBean#0,type=MethodInvokingRouter
. There is no difference between these MBeans (aside from the object name), except that the statistics are not enabled (the attributes are0
) by exporters other than the integration exporter. You can enable statistics at runtime by using the JMX operations. When exported by the integration MBean exporter, the initial state can be managed as described earlier.If you currently use the second MBean to change, for example, channel mappings and you use the integration MBean exporter, note that the object name has changed because of the MBean consolidation. There is no change if you are not using the integration MBean exporter.
-
- MBean Exporter Bean Name Patterns
-
Previously, the
managed-components
patterns were inclusive only. If a bean name matched one of the patterns, it would be included. Now, the pattern can be negated by prefixing it with!
. For example,!thing*, things
matches all bean names that do not start withthing
exceptthings
. Patterns are evaluated left to right. The first match (positive or negative) wins, and then no further patterns are applied.The addition of this syntax to the pattern causes one possible (although perhaps unlikely) problem. If you have a bean named "!thing"
and you included a pattern of!thing
in your MBean exporter’smanaged-components
patterns, it no longer matches; the pattern now matches all beans not namedthing
. In this case, you can escape the!
in the pattern with\
. The\!thing
pattern matches a bean named!thing
. - IntegrationMBeanExporter changes
-
The
IntegrationMBeanExporter
no longer implementsSmartLifecycle
. This means thatstart()
andstop()
operations are no longer available to register and unregister MBeans. The MBeans are now registered during context initialization and unregistered when the context is destroyed.
Orderly Shutdown Managed Operation
The MBean exporter provides a JMX operation to shut down the application in an orderly manner, intended for use before terminating the JVM. The following example shows how to use it:
public void stopActiveComponents(long howLong)
Its use and operation are described in Orderly Shutdown.