diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java index ca6c2f9dab..beda2d4c8f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java @@ -138,6 +138,18 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa protected abstract Object handleRequestMessage(Message requestMessage); + /** + * An implementation of this interface is used to wrap the + * {@link AbstractReplyProducingMessageHandler#handleRequestMessage(Message)} + * method. Also allows access to the underlying + * {@link AbstractReplyProducingMessageHandler} to obtain properties. + * + * @author Gary Russell + * @since 2.2 + * + * @see #getAdvisedHandler() + * + */ public interface RequestHandler { Object handleRequestMessage(Message requestMessage); @@ -145,6 +157,18 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa @Override String toString(); + /** + * Utility method, intended for use in message handler advice classes to get + * information about the advised object. For example: + *

+ * {@code ((AbstractReplyProducingMessageHandler.RequestHandler) + * invocation.getThis()).getAdvisedHandler().getComponentName()} + * @return the outer class instance. + * + * @since 4.3.2 + */ + AbstractReplyProducingMessageHandler getAdvisedHandler(); + } private class AdvisedRequestHandler implements RequestHandler { @@ -159,6 +183,11 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa return AbstractReplyProducingMessageHandler.this.toString(); } + @Override + public AbstractReplyProducingMessageHandler getAdvisedHandler() { + return AbstractReplyProducingMessageHandler.this; + } + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java index 94e882a17f..c5e3eb2652 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/advice/AdvisedMessageHandlerTests.java @@ -132,6 +132,8 @@ public class AdvisedMessageHandlerTests { return "baz"; } }; + String componentName = "testComponentName"; + handler.setComponentName(componentName); QueueChannel replies = new QueueChannel(); handler.setOutputChannel(replies); Message message = new GenericMessage("Hello, world!"); @@ -153,6 +155,17 @@ public class AdvisedMessageHandlerTests { List adviceChain = new ArrayList(); adviceChain.add(advice); + final AtomicReference compName = new AtomicReference(); + adviceChain.add(new AbstractRequestHandlerAdvice() { + + @Override + protected Object doInvoke(ExecutionCallback callback, Object target, Message message) throws Exception { + compName.set(((AbstractReplyProducingMessageHandler.RequestHandler) target).getAdvisedHandler() + .getComponentName()); + return callback.execute(); + } + + }); handler.setAdviceChain(adviceChain); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); @@ -163,6 +176,8 @@ public class AdvisedMessageHandlerTests { assertNotNull(reply); assertEquals("baz", reply.getPayload()); + assertEquals(componentName, compName.get()); + Message success = successChannel.receive(1000); assertNotNull(success); assertEquals("Hello, world!", ((AdviceMessage) success).getInputMessage().getPayload()); diff --git a/src/reference/asciidoc/handler-advice.adoc b/src/reference/asciidoc/handler-advice.adoc index aafa627446..685e2b62d6 100644 --- a/src/reference/asciidoc/handler-advice.adoc +++ b/src/reference/asciidoc/handler-advice.adoc @@ -395,7 +395,7 @@ If you wish to suppress throwing the exception, set the `trapException` property ==== Custom Advice Classes In addition to the provided Advice classes above, you can implement your own Advice classes. -While you can provide any implementation of `org.aopalliance.aop.Advice`, it is generally recommended that you subclass `o.s.i.handler.advice.AbstractRequestHandlerAdvice`. +While you can provide any implementation of `org.aopalliance.aop.Advice` (usually `org.aopalliance.intercept.MethodInterceptor`), it is generally recommended that you subclass `o.s.i.handler.advice.AbstractRequestHandlerAdvice`. This has the benefit of avoiding writing low-level _Aspect Oriented Programming_ code as well as providing a starting point that is specifically tailored for use in this environment. Subclasses need to implement the `doInvoke()`` method: @@ -530,6 +530,42 @@ You may want to place the retry advice advice first, followed by the transaction Then, each retry will be performed in a new transaction. On the other hand, if you want all the attempts, and any recovery operations (in the retry `RecoveryCallback`), to be scoped within the transaction, you would put the transaction advice first. +[[advised-handler-properties]] +==== Advised Handler Properties + +Sometimes, it is useful to access handler properties from within the advice. +For example, most handlers implement `NamedComponent` and you can access the component name. + +The target object can be accessed via the `target` argument when subclassing `AbstractRequestHandlerAdvice` or +`invocation.getThis()` when implementing `org.aopalliance.intercept.MethodInterceptor`. + +When the entire handler is advised (such as when the handler does not produce replies, or the advice implements `HandleMessageAdvice`), you can simply cast the target object to the desired implemented interface, such as `NamedComponent`. + +[source, java] +---- +String componentName = ((NamedComponent) target).getComponentName(); +---- + +or + +[source, java] +---- +String componentName = ((NamedComponent) invocation.getThis()).getComponentName(); +---- + +when implementing `MethodInterceptor` directly. + +When only the `handleRequestMessage()` method is advised (in a reply-producing handler), you need to access the +full handler, which is an `AbstractReplyProducingMessageHandler`... + +[source, java] +---- +AbstractReplyProducingMessageHandler handler = + ((AbstractReplyProducingMessageHandler.RequestHandler) target).getAdvisedHandler(); + +String componentName = handler.getComponentName(); +---- + [[idempotent-receiver]] ==== Idempotent Receiver Enterprise Integration Pattern