[[jmx]]
= JMX Support

Spring Integration provides channel Adapters for receiving and publishing JMX Notifications.

You need to include this dependency into your project:

[tabs]
======
Maven::
+
[source, xml, subs="normal", role="primary"]
----
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-jmx</artifactId>
    <version>{project-version}</version>
</dependency>
----

Gradle::
+
[source, groovy, subs="normal", role="secondary"]
----
compile "org.springframework.integration:spring-integration-jmx:{project-version}"
----
======

An inbound channel adapter allows for polling JMX MBean attribute values, and an outbound channel adapter allows for invoking JMX MBean operations.

[[jmx-notification-listening-channel-adapter]]
== 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:

[source,xml]
----
<int-jmx:notification-listening-channel-adapter id="adapter"
    channel="channel"
    object-name="example.domain:name=publisher"/>
----

TIP: 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:

[source,xml]
----
<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.

[NOTE]
====
For this component only, the `object-name` attribute can contain an object name pattern (for example,
"org.something:type=MyType,name=*").
In that case, the adapter receives notifications from all MBeans with object names that match the pattern.
In addition, the `object-name` attribute can contain a SpEL reference to a `<util:list>` of object name patterns, as the following example shows:

[source,xml]
----
<jmx:notification-listening-channel-adapter id="manyNotificationsAdapter"
    channel="manyNotificationsChannel"
    object-name="#{patterns}"/>

<util:list id="patterns">
    <value>org.foo:type=Foo,name=*</value>
    <value>org.foo:type=Bar,name=*</value>
</util:list>
----

The names of the located MBean(s) are logged when DEBUG level logging is enabled.
====

[[jmx-notification-publishing-channel-adapter]]
== 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:

[source,xml]
----
<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:

[source,xml]
----
<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"/>
----

[[jmx-attribute-polling-channel-adapter]]
== 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 configure 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 xref:jmx.adoc#jmx-notification-listening-channel-adapter[described earlier].
The following example shows how to configure an attribute-polling channel adapter with XML:

[source,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]]
== 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 xref:jmx.adoc#jmx-notification-listening-channel-adapter[described earlier].
The following example shows how to configure a tree-polling channel adapter with XML:

[source,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 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.
// TODO How can people implement their own filters? This needs at least a reference to which class to extend or interface to implement. An example would be better still.

[[jmx-operation-invoking-channel-adapter]]
== 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:

[source,xml]
----
<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.

[[jmx-operation-invoking-outbound-gateway]]
== 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:

[source,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.

[[jmx-mbean-exporter]]
== 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:

[source,xml]
----
<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>
----

[IMPORTANT]
=====
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 `<context:mbean-export/>` tag.
The exporter has some metrics attached to it -- for instance, a count of the number of handlers and the number of queued messages.

It also has a useful operation, as discussed in xref:jmx.adoc#jmx-mbean-shutdown[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:

[source,java]
----
@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.

[[jmx-mbean-features]]
=== 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:

.MBean Object Names
[cols="1,3l", options="header"]
|===
| 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 ObjectName Part
[cols="1,3", options="header"]
|===
| Bean Value
| Description

| endpoint
| The bean name of the enclosing endpoint (for example `<service-activator>`), if there is one

| 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 `toString()` method of the object being monitored (handler or source)

|===

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 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jmx/export/naming/ObjectNamingStrategy.html[`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:

[source,java]
----
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.

NOTE: The default naming strategy is a https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jmx/export/naming/MetadataNamingStrategy.html[`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-42-improvements]]
=== 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.

@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 an `IntegrationMBeanExporter`.
+
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 context `MBeanServer` or by an `IntegrationMBeanExporter` (but not both -- if both exporters are present, the bean is exported by the integration exporter if the bean matches a `managed-components` pattern).

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 with `thing` except `things`.
Patterns are evaluated left to right.
The first match (positive or negative) wins, and then no further patterns are applied.
+
WARNING: 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's `managed-components` patterns, it no longer matches; the pattern now matches all beans not named `thing`.
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 implements `SmartLifecycle`.
This means that `start()` and `stop()` 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.

[[jmx-mbean-shutdown]]
=== Orderly Shutdown Managed Operation

The MBean exporter lets a JMX operation shut down the application in an orderly manner.
It is intended for use before stopping the JVM.
The following example shows how to use it:

[source,java]
----
public void stopActiveComponents(long howLong)
----

Its use and operation are described in xref:shutdown.adoc[Orderly Shutdown].
