From 134c7c870b35f15b97b37bf13eeeaf060d671527 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 2 Mar 2015 14:07:53 +0200 Subject: [PATCH] INT-3651: JMX Improvements Documentation JIRA: https://jira.spring.io/browse/INT-3651 - Add documentation for the new JMX environment - Add the ability to customize the default metrics implementations - Fix LifecycleMessageHandlerMetrics to get a custom `MessageHandlerMetrics` - Add an escape to the bean pattern matcher to handle beans starting with `!` INT-3651: More Docs/Polishing * JavaDocs polishing * Change `jmx.xml` to describe `public void stopActiveComponents(long howLong)` not that removed with `boolean force` --- .../DefaultMessageChannelMetrics.java | 49 ++- .../AbstractMessageHandlerMetrics.java | 4 +- .../DefaultMessageHandlerMetrics.java | 25 +- .../ExponentialMovingAverageRate.java | 2 +- .../ExponentialMovingAverageRatio.java | 2 +- .../monitor/IntegrationMBeanExporter.java | 3 + .../LifecycleMessageHandlerMetrics.java | 13 +- .../MBeanExporterParserTests-context.xml | 7 +- .../jmx/config/MBeanExporterParserTests.java | 59 +++ src/reference/docbook/jmx.xml | 375 ++++++++++++++++-- src/reference/docbook/whats-new.xml | 14 + 11 files changed, 509 insertions(+), 44 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/channel/management/DefaultMessageChannelMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/channel/management/DefaultMessageChannelMetrics.java index 6ace7ec15f..1124dd367c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/channel/management/DefaultMessageChannelMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/channel/management/DefaultMessageChannelMetrics.java @@ -25,8 +25,7 @@ import org.springframework.integration.support.management.MetricsContext; import org.springframework.integration.support.management.Statistics; /** - * Registers all message channels, and accumulates statistics about their performance. The statistics are then published - * locally for other components to consume and publish remotely. + * Default implementation; use the full constructor to customize the moving averages. * * @author Dave Syer * @author Helena Edelson @@ -43,17 +42,13 @@ public class DefaultMessageChannelMetrics extends AbstractMessageChannelMetrics public static final int DEFAULT_MOVING_AVERAGE_WINDOW = 10; - private final ExponentialMovingAverage sendDuration = new ExponentialMovingAverage( - DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.); + private final ExponentialMovingAverage sendDuration; - private final ExponentialMovingAverageRate sendErrorRate = new ExponentialMovingAverageRate( - ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true); + private final ExponentialMovingAverageRate sendErrorRate; - private final ExponentialMovingAverageRatio sendSuccessRatio = new ExponentialMovingAverageRatio( - ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true); + private final ExponentialMovingAverageRatio sendSuccessRatio; - private final ExponentialMovingAverageRate sendRate = new ExponentialMovingAverageRate( - ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true); + private final ExponentialMovingAverageRate sendRate; private final AtomicLong sendCount = new AtomicLong(); @@ -64,11 +59,43 @@ public class DefaultMessageChannelMetrics extends AbstractMessageChannelMetrics protected final AtomicLong receiveErrorCount = new AtomicLong(); public DefaultMessageChannelMetrics() { - super(null); + this(null); } + /** + * Construct an instance with default metrics with {@code window=10, period=1 second, + * lapsePeriod=1 minute}. + * @param name the name. + */ public DefaultMessageChannelMetrics(String name) { + this(name, new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.), + new ExponentialMovingAverageRate( + ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true), + new ExponentialMovingAverageRatio( + ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true), + new ExponentialMovingAverageRate( + ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true)); + } + + /** + * Construct an instance with the supplied metrics. For proper representation of metrics, the + * supplied sendDuration must have a {@code factor=1000000.} and the the other arguments + * must be created with the {@code millis} constructor argument set to true. + * @param name the name. + * @param sendDuration an {@link ExponentialMovingAverage} for calculating the send duration. + * @param sendErrorRate an {@link ExponentialMovingAverageRate} for calculating the send error rate. + * @param sendSuccessRatio an {@link ExponentialMovingAverageRatio} for calculating the success ratio. + * @param sendRate an {@link ExponentialMovingAverageRate} for calculating the send rate. + * @since 4.2 + */ + public DefaultMessageChannelMetrics(String name, ExponentialMovingAverage sendDuration, + ExponentialMovingAverageRate sendErrorRate, ExponentialMovingAverageRatio sendSuccessRatio, + ExponentialMovingAverageRate sendRate) { super(name); + this.sendDuration = sendDuration; + this.sendErrorRate = sendErrorRate; + this.sendSuccessRatio = sendSuccessRatio; + this.sendRate = sendRate; } public void destroy() { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AbstractMessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AbstractMessageHandlerMetrics.java index f3a0c28526..ef92188342 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AbstractMessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/AbstractMessageHandlerMetrics.java @@ -58,13 +58,13 @@ public abstract class AbstractMessageHandlerMetrics implements ConfigurableMetri /** * Begin a handle event. * @param message the message to handle. - * @return the context. + * @return the context to be used in the {@link #afterHandle(MetricsContext, boolean)}. */ public abstract MetricsContext beforeHandle(Message message); /** * End a handle event - * @param context the context. + * @param context the context from the previous {@link #beforeHandle(Message)}. * @param success true for success, false otherwise. */ public abstract void afterHandle(MetricsContext context, boolean success); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/DefaultMessageHandlerMetrics.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/DefaultMessageHandlerMetrics.java index 208f42484e..a574d490c9 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/management/DefaultMessageHandlerMetrics.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/management/DefaultMessageHandlerMetrics.java @@ -24,6 +24,8 @@ import org.springframework.integration.support.management.Statistics; import org.springframework.messaging.Message; /** + * Default implementation; use the full constructor to customize the moving averages. + * * @author Dave Syer * @author Gary Russell * @since 2.0 @@ -39,17 +41,32 @@ public class DefaultMessageHandlerMetrics extends AbstractMessageHandlerMetrics private final AtomicLong errorCount = new AtomicLong(); - private final ExponentialMovingAverage duration = new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW, - 1000000.); + private final ExponentialMovingAverage duration; public DefaultMessageHandlerMetrics() { - super(null); + this(null); } + /** + * Construct an instance with the default moving average window (10). + * @param name the name. + */ public DefaultMessageHandlerMetrics(String name) { - super(name); + this(name, new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.)); } + /** + * Construct an instance with the supplied {@link ExponentialMovingAverage} calculating + * the duration of processing by the message handler (and any downstream synchronous + * endpoints). + * @param name the name. + * @param duration an {@link ExponentialMovingAverage} for calculating the duration. + * @since 4.2 + */ + public DefaultMessageHandlerMetrics(String name, ExponentialMovingAverage duration) { + super(name); + this.duration = duration; + } @Override public MetricsContext beforeHandle(Message message) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRate.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRate.java index 86e08c3c2a..5a2f250d00 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRate.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRate.java @@ -105,7 +105,7 @@ public class ExponentialMovingAverageRate { /** * Add a new event to the series at time t. - * @param t a new event to the series in milliseconds. + * @param t a new event to the series (System.nanoTime()). */ public synchronized void increment(long t) { if (this.times.size() == this.retention) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRatio.java b/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRatio.java index cb6b0d9216..a4a2fcfe6a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRatio.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/management/ExponentialMovingAverageRatio.java @@ -92,7 +92,7 @@ public class ExponentialMovingAverageRatio { /** * Add a new event with successful outcome at time t. - * @param t the time in milliseconds. + * @param t the System.nanoTime(). */ public void success(long t) { append(1, t); diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java index 02874e0e2e..33455a75bf 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java @@ -915,6 +915,9 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP reverse = true; patternToUse = pattern.substring(1); } + else if (pattern.startsWith("\\")) { + patternToUse = pattern.substring(1); + } if (PatternMatchUtils.simpleMatch(patternToUse, name)) { return !reverse; } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java index 9a52bddf22..7d42a20837 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMetrics.java @@ -17,7 +17,9 @@ package org.springframework.integration.monitor; import org.springframework.context.Lifecycle; +import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; import org.springframework.integration.handler.management.MessageHandlerMetrics; +import org.springframework.integration.support.management.ConfigurableMetricsAware; import org.springframework.integration.support.management.IntegrationManagedResource; import org.springframework.integration.support.management.Statistics; import org.springframework.jmx.export.annotation.ManagedAttribute; @@ -32,7 +34,8 @@ import org.springframework.jmx.export.annotation.ManagedOperation; * @since 2.0 */ @IntegrationManagedResource -public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Lifecycle { +public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Lifecycle, + ConfigurableMetricsAware { private final Lifecycle lifecycle; @@ -44,6 +47,14 @@ public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Li this.delegate = delegate; } + @SuppressWarnings("unchecked") + @Override + public void configureMetrics(AbstractMessageHandlerMetrics metrics) { + if (this.delegate instanceof ConfigurableMetricsAware) { + ((ConfigurableMetricsAware) this.delegate).configureMetrics(metrics); + } + } + @Override @ManagedAttribute public boolean isRunning() { diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml index 4b28981162..73a485e79a 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml @@ -22,6 +22,7 @@ object-naming-strategy="keyNamer" counts-enabled="foo, !baz, ba*" stats-enabled="fiz, buz" + managed-components="\!excluded, f*, b*, q*, t*" metrics-factory="mf" /> @@ -43,6 +44,10 @@ - + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java index 9e1048c203..282538a76f 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java @@ -31,9 +31,17 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.integration.channel.management.AbstractMessageChannelMetrics; +import org.springframework.integration.channel.management.DefaultMessageChannelMetrics; import org.springframework.integration.channel.management.MessageChannelMetrics; +import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics; +import org.springframework.integration.handler.management.DefaultMessageHandlerMetrics; +import org.springframework.integration.handler.management.MessageHandlerMetrics; import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.integration.monitor.MetricsFactory; +import org.springframework.integration.support.management.ExponentialMovingAverage; +import org.springframework.integration.support.management.ExponentialMovingAverageRate; +import org.springframework.integration.support.management.ExponentialMovingAverageRatio; import org.springframework.integration.test.util.TestUtils; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -68,6 +76,9 @@ public class MBeanExporterParserTests { MessageChannelMetrics metrics = context.getBean("foo", MessageChannelMetrics.class); assertTrue(metrics.isCountsEnabled()); assertFalse(metrics.isStatsEnabled()); + checkCustomized(metrics); + MessageHandlerMetrics handlerMetrics = context.getBean("transformer.handler", MessageHandlerMetrics.class); + checkCustomized(handlerMetrics); metrics = context.getBean("bar", MessageChannelMetrics.class); assertTrue(metrics.isCountsEnabled()); assertFalse(metrics.isStatsEnabled()); @@ -83,9 +94,57 @@ public class MBeanExporterParserTests { metrics = context.getBean("buz", MessageChannelMetrics.class); assertTrue(metrics.isCountsEnabled()); assertTrue(metrics.isStatsEnabled()); + metrics = context.getBean("!excluded", MessageChannelMetrics.class); + assertFalse(metrics.isCountsEnabled()); + assertFalse(metrics.isStatsEnabled()); + checkCustomized(metrics); MetricsFactory factory = context.getBean(MetricsFactory.class); assertSame(factory, TestUtils.getPropertyValue(exporter, "metricsFactory")); exporter.destroy(); } + private void checkCustomized(MessageChannelMetrics metrics) { + assertEquals(20, TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.window")); + assertEquals(1000000., TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.factor", Double.class), + .01); + assertEquals(30, TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.window")); + assertEquals(2000000., + TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.period", Double.class), .01); + assertEquals(.001 / 120000, + TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.lapse", Double.class), .01); + + assertEquals(40, TestUtils.getPropertyValue(metrics, "channelMetrics.sendSuccessRatio.window")); + assertEquals(.001 / 130000, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.lapse", Double.class), + .01); + + assertEquals(50, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.window")); + assertEquals(3000000., TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.period", Double.class), .01); + assertEquals(.001 / 140000, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.lapse", Double.class), + .01); + } + + private void checkCustomized(MessageHandlerMetrics metrics) { + assertEquals(20, TestUtils.getPropertyValue(metrics, "handlerMetrics.duration.window")); + assertEquals(1000000., TestUtils.getPropertyValue(metrics, "handlerMetrics.duration.factor", Double.class), + .01); + } + + public static class CustomMetrics implements MetricsFactory { + + @Override + public AbstractMessageChannelMetrics createChannelMetrics(String name) { + return new DefaultMessageChannelMetrics(name, + new ExponentialMovingAverage(20, 1000000.), + new ExponentialMovingAverageRate(2000, 120000, 30, true), + new ExponentialMovingAverageRatio(130000, 40, true), + new ExponentialMovingAverageRate(3000, 140000, 50, true)); + } + + @Override + public AbstractMessageHandlerMetrics createHandlerMetrics(String name) { + return new DefaultMessageHandlerMetrics(name, new ExponentialMovingAverage(20, 1000000.)); + } + + } + } diff --git a/src/reference/docbook/jmx.xml b/src/reference/docbook/jmx.xml index 375f4eae88..e8cc02d4ae 100644 --- a/src/reference/docbook/jmx.xml +++ b/src/reference/docbook/jmx.xml @@ -248,20 +248,6 @@ ]]> - - Once the exporter is defined, start up your application with: - - -Dcom.sun.management.jmxremote - -Dcom.sun.management.jmxremote.port=6969 - -Dcom.sun.management.jmxremote.ssl=false - -Dcom.sun.management.jmxremote.authenticate=false - - Then start JConsole (free with the JDK), and connect to the local process on - localhost:6969 to get a look at the management - endpoints exposed. (The port and client are just examples to get you - started quickly, there are other JMX clients available and some offer more - sophisticated features than JConsole.) - @@ -441,7 +427,7 @@ public class ContextConfiguration { cases there are some metrics that are simple counters (message count and error count), and some that are estimates of averages of interesting quantities. The algorithms used to calculate these - estimates are described briefly in the table below: + estimates are described briefly in the section below. @@ -462,17 +448,25 @@ public class ContextConfiguration { Count Send Count - Simple incrementer. Increase by one when an event + Simple incrementer. Increases by one when an event occurs. + + Error Count + Send Error Count + + Simple incrementer. Increases by one when an send results + in an error. + + Duration Send Duration (method execution time in milliseconds) - Exponential Moving Average with decay factor 10. Average - of the method execution time over roughly the last 10 + Exponential Moving Average with decay factor (10 by default). Average + of the method execution time over roughly the last 10 (default) measurements. @@ -480,23 +474,97 @@ public class ContextConfiguration { RateSend Rate (number of operations per second)Inverse of Exponential Moving Average of the interval - between events with decay in time (lapsing over 60 seconds) and - per measurement (last 10 events). + between events with decay in time (lapsing over 60 seconds + by default) and per measurement (last 10 events by default). + + + + Error Rate + Send Error Rate (number of errors per second) + Inverse of Exponential Moving Average of the interval + between error events with decay in time (lapsing over 60 seconds + by default) and per measurement (last 10 events by default). Ratio - Send Error Ratio (ratio of errors to total sends) + Send Success Ratio (ratio of successful to total sends) Estimate the success ratio as the Exponential Moving Average of the series composed of values 1 for success and 0 for failure (decaying as per the rate measurement over time and - events). Error ratio is 1 - success ratio. + events by default). Error ratio is 1 - success ratio.
+ +
+ MessageHandler MBean Features + + The following table shows the statistics maintained for message + handlers. Some metrics are simple counters (message + count and error count), and one is an estimate of averages + of send duration. The algorithms used to calculate these + estimates are described briefly in the table below: + + + + + + <tgroup cols="3"> + <colspec colnum="1" colname="col1" colwidth="1*"/> + <colspec colnum="2" colname="col2" colwidth="1.5*"/> + <colspec colnum="3" colname="col3" colwidth="3*"/> + <thead> + <row> + <entry align="center">Metric Type</entry> + <entry align="center">Example</entry> + <entry align="center">Algorithm</entry> + </row> + </thead> + <tbody> + <row> + <entry>Count</entry> + <entry>Handle Count</entry> + <entry>Simple incrementer. Increases by one when an event + occurs. + </entry> + </row> + <row> + <entry>Error Count</entry> + <entry>Handler Error Count</entry> + <entry> + Simple incrementer. Increases by one when an invocation results + in an error. + </entry> + </row> + <row> + <entry>Active Count</entry> + <entry>Handler Active Count</entry> + <entry> + Indicates the number of currently active threads currently invoking + the handler (or any downstream synchronous flow). + </entry> + </row> + <row> + <entry>Duration</entry> + <entry>Handle Duration (method execution time in + milliseconds) + </entry> + <entry>Exponential Moving Average with decay factor (10 by default). Average + of the method execution time over roughly the last 10 (default) + measurements. + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> + + <section id="jmx-statistics"> + <title>Time-Based Average Estimates A feature of the time-based average estimates is that they decay with time if no new measurements arrive. To help interpret the behaviour @@ -534,6 +602,267 @@ public class ContextConfiguration { seconds). + +
+ 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, but 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 + and MessageHandler 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; but they are still enabled + (by default) only if the integration MBean exporter is declared. + + + This change means that you no longer automatically get an MBean or statistics for custom + MessageHandler implementations, unless those custom + handlers extend AbstractMessageHandler. The simplest + way to resolve this is to extend AbstractMessageHandler. + If that's not possible, or desired, another work-around is to implement the + MessageHandlerMetrics interface. For convenience, + a DefaultMessageHandlerMetrics is provided to capture + and report statistics. Invoke the beforeHandle and + afterHandleat the appropriate times. Your + MessageHandlerMetrics methods can then delegate to this + object to obtain each statistic. Similarly, MessageSource + implementations must extend AbstractMessageSource + or implement MessageSourceMetrics. Message sources + only capture a count so there is no provided convenience class; simply maintain + the count in an AtomicLong field. + + + The removal of the proxy has two additional benefits; 1) stack traces in + exceptions are reduced (when JMX is enabled) because the proxy is not on the + stack; 2) cases where 2 MBeans were exported for the same bean now only + export a single MBean with consolidated attributes/operations (see the MBean + consolidation bullet below). + + + + Resolution + + System.nanoTime() is now used to capture times instead of + System.currentTimeMillis(). This may provide more accuracy on + some JVMs, espcially when durations of less than 1 millisecond are expected + + + + Setting Initial Statistics Collection State + + Previously, when JMX was enabled, all sources, channels, handlers captured + statistics. It is now possible to control whether the statisics are enabled + on an individual component. Further, it is possible to capture simple counts + on MessageChannels and + MessageHandlers instead of the complete + time-based statistics. This can have significant performance implications + because you can selectively configure where you need detailed statistics, + as well as enable/disable at runtime. Also see the bullet below about + setting initial collection state. + + + Two new attributes have been added to the <int-jmx:mbean-exporter/>. + counts-enabled is a list of bean name patterns where simple message counts + will be enabled. stats-enabled is a list of bean name patterns where full + time-based statistics will be enabled. These are initial settings only and each component + can have its settings changed at runtime, using JMX or a <control-bus/> using the + enableCounts() and enableStats() operations. + Note: stats is a superset of counts, enabling stats + will enable counts (this is true for the initial setting via the patterns and at + runtime). Disabling counts at runtime will also disable stats. + + + A pattern can be negated by preceding it with !; patterns are evaluated + left to right; the first match (positive or negative) wins and the remaining + patterns won't be evaluated against that bean. If your bean name begins with + !, the ! in the pattern can be escaped. "\!foo" + will positively match a bean named "!foo". + + + + @IntegrationManagedResource + + Similar to the @ManagedResource annotation, the + @IntegrationManagedResource marks a class as eligible + to be exported as an MBean; however, it will only be exported if there is + an IntegrationMBeanExporter in the application + context. + + + 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 bullet). Such MBeans will be exported by any + context MBeanServer or 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). + + + + Consolidated MBeans + + Certain classes within the framework (mapping routers for example) have additional + attributes/operations over and above those provided by metrics and + Lifecycle. We will use a Router as an example here. + + + Previously, beans of these types were exported as two distinct MBeans: 1) the + metrics MBean (with an objectName such as: intDomain:type=MessageHandler,name=myRouter,bean=endpoint). + This MBean had metrics attributes and metrics/Lifecycle operations. + + + A second MBean (with an objectName 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 + objectName will depend on the exporter. If exported by the integration + MBean exporter, the objectName will be, for example: intDomain:type=MessageHandler,name=myRouter,bean=endpoint. If exported + by another exporter, the objectName will be, for example: ctxDomain:name=org.springframework.integration.config.RouterFactoryBean#0 + ,type=MethodInvokingRouter. There is no difference between these MBeans (aside from + the objectName), except that the statistics will not + be enabled (the attributes will be 0) by exporters other than the integration exporter; + statistics can be enabled at runtime using the JMX operations. When exported + by the integration MBean exporter, the initial state can be managed as described above. + + + If you are currently using the second MBean to change, for example, channel mappings, + and you are using the integration MBean + exporter, note that the objectName 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 !. i.e. "!foo*, foox" will match + all beans that don't start with foo, except foox. Patterns + are evaluated left to right and the first match (positive or negative) wins and no + further patterns are applied. + + + The addition of this syntax to the pattern causes one possible (although perhaps unlikey) + problem. If you have a bean "!foo" and + you included a pattern "!foo" in your MBean exporter's + managed-components patterns; it will no long match; the pattern will now match all + beans not named foo. In this case, you + can escape the ! in the pattern with \. The pattern + "\!foo" means match a bean named "!foo". + + + + Replacing the Default Channel/Handler Statistics + + A new strategy interface MetricsFactory has been introduced + allowing you to provide custom channel metrics for your MessageChannels + and MessageHandlers. By default, a + DefaultMetricsFactory provides default implementation of + MessageChannelMetrics and + MessageHandlerMetrics which are described in the next bullet. + To override the default MetricsFactory use the MBean exporter's + metrics-factory attribute to provide a reference to your + MetricsFactory bean instance. You can either customize the + default implementations as described in the next bullet, or provide completely different + implementations by overriding AbstractMessageChannelMetrics + and/or AbstractMessageHandlerMetrics. + + + + Customizing the Default Channel/Handler Statistics + + See and the Javadocs for the + ExponentialMovingAverage* classes for more information about these + values. + + + By default, the DefaultMessageChannelMetrics and + DefaultMessageHandlerMetrics use a window of + 10 measurements, a rate period of 1 second (rate per second) and a decay lapse period + of 1 minute. + + + If you wish to override these defaults, you can provide a custom + MetricsFactory that returns appropriately configured + metrics and provide a reference to it to the MBean exporter as described above. + + + Example: + + + + + + + Advanced Customization + + The customizations described above are wholesale and will apply to all appropriate + beans exported by the MBean exporter. This is the extent of customization available + using XML configuration. + + + Individual beans can be provided with different implementations using java + @Configuration or programmatically at runtime, after the application + context has been refreshed, by invoking the configureMetrics methods + on AbstractMessageChannel and + AbstractMessageHandler. + + + + Performance Improvement + + Previously, the time-based metrics (see ) were + calculated in real time. The statistics are now calculated when retrieved instead. + This resulted in a significant performance improvement, at the expense of a + small amount of additional memory for each statistic. As discussed in the bullet + above, the statistics can be disabled altogether, while retaining the MBean + allowing the invocation of Lifecycle methods. + + + +
+
Orderly Shutdown Managed Operation @@ -541,7 +870,7 @@ public class ContextConfiguration { The MBean exporter provides a JMX operation to shut down the application in an orderly manner, intended for use before terminating the JVM. - Its use and operation are described in . diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index b555fa7ecd..98cb872dfc 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -11,6 +11,20 @@
New Components +
+ Major JMX Rework + + A new MetricsFactory strategy interface has been introduced. This, + together with other changes in the JMX infrastructure provides much more control + over JMX configuration and runtime performance. + + + However, this has some important implications for (some) user environments. + + + For complete details, see . + +
General Changes