INT-3186 Fix Metrics For Direct MessageHandler

When a simple MessageHandler is referenced from a
`<service-activator/>`, it is wrapped in an anonymous
AbstractReplyProducingMessageHandler to facilitate proper handling of
the `<request-handler-advice-chain/>` and so that normal
'produced no reply` messages are logged.

Previously, this caused 2 MBeans to be exposed, one for tha actual
handler; one for the wrapper.

This added more stack frames between the dispatcher and the
handler (because 2 sets of statistics were captured).

The root cause was that the MBean exporter was not aware of the
relationship between these objects.

https://jira.springsource.org/browse/INT-3186

Add code to the IntegrationMBeanExporter to suppress adding
metrics to the wrapper.

This involves detecting that it is a wrapper and not exposing
it as an MBean and, when matching handlers with endpoints,
checking that the wrapped handler is the actual handler for the endpoint.

Update test to reflect the reduced number of stack frames between
the dispatcher and handler.

Also add tests to verify the detection of multiple references to
the same ARPMH.

INT-3186: `IntegrationMBeanExporter` optimization
This commit is contained in:
Gary Russell
2013-10-31 15:37:50 +02:00
committed by Artem Bilan
parent cc434db959
commit eaa28a9dbf
8 changed files with 144 additions and 19 deletions

View File

@@ -73,7 +73,7 @@ public class ServiceActivatorFactoryBean extends AbstractStandardMessageHandlerF
}
/*
* Return a reply-producing message handler so that we still get 'produced no reply' messages
* and the super class will inject the advice chain to advise the handler if needed.
* and the super class will inject the advice chain to advise the handler method if needed.
*/
handler = new AbstractReplyProducingMessageHandler() {

View File

@@ -22,19 +22,19 @@
<service-activator id="replyingHandlerWithStandardMethodTestService"
input-channel="replyingHandlerWithStandardMethodTestInputChannel"
method="handleMessage">
<beans:bean
<beans:bean id="innerReplyingHandler"
class="org.springframework.integration.handler.ServiceActivatorDefaultFrameworkMethodTests$TestReplyingMessageHandler"/>
</service-activator>
<service-activator id="replyingHandlerWithOtherMethodTestService"
input-channel="replyingHandlerWithOtherMethodTestInputChannel"
method="foo">
<beans:bean
<beans:bean id="innerReplyingHandlerFoo"
class="org.springframework.integration.handler.ServiceActivatorDefaultFrameworkMethodTests$TestReplyingMessageHandler"/>
</service-activator>
<service-activator id="handlerTestService" input-channel="handlerTestInputChannel">
<beans:bean
<beans:bean id="innerHandler"
class="org.springframework.integration.handler.ServiceActivatorDefaultFrameworkMethodTests$TestMessageHandler"/>
</service-activator>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<service-activator id="optimizedRefReplyingHandlerTestService1"
input-channel="optimizedRefReplyingHandlerTestInputChannel" ref="testReplyingMessageHandler"/>
<service-activator id="optimizedRefReplyingHandlerTestService2"
input-channel="optimizedRefReplyingHandlerTestInputChannel" ref="testReplyingMessageHandler"/>
<beans:bean id="testReplyingMessageHandler"
class="org.springframework.integration.handler.ServiceActivatorDefaultFrameworkMethodTests$TestReplyingMessageHandler"/>
</beans:beans>

View File

@@ -18,11 +18,16 @@ package org.springframework.integration.handler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -149,6 +154,22 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
assertEquals("processorTestInputChannel,processorTestService", reply.getHeaders().get("history").toString());
}
@Test
public void testFailOnDoubleReference() {
try {
new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-fail-context.xml",
this.getClass());
fail("Expected exception due to 2 endpoints referencing the same bean");
}
catch (Exception e) {
assertThat(e, Matchers.instanceOf(BeanCreationException.class));
assertThat(e.getCause(), Matchers.instanceOf(BeanCreationException.class));
assertThat(e.getCause().getCause(), Matchers.instanceOf(IllegalArgumentException.class));
assertThat(e.getCause().getCause().getMessage(),
Matchers.containsString("An AbstractReplyProducingMessageHandler may only be referenced once"));
}
}
@SuppressWarnings("unused")
private static class TestReplyingMessageHandler extends AbstractReplyProducingMessageHandler {