diff --git a/docs/src/reference/docbook/message-publishing.xml b/docs/src/reference/docbook/message-publishing.xml index f599808dfc..4e5dbd59ee 100644 --- a/docs/src/reference/docbook/message-publishing.xml +++ b/docs/src/reference/docbook/message-publishing.xml @@ -3,7 +3,7 @@ xmlns:xlink="http://www.w3.org/1999/xlink"> Message Publishing - The AOP Message Publishing feature allows you to construct and send a message as a by-product of method invocation. For example, imagine you + The AOP Message Publishing feature allows you to construct and send a message as a by-product of a method invocation. For example, imagine you have a component and every time the state of this component changes you would like to be notified via a Message. The easiest way to send such notifications would be to send a message to a dedicated channel, but how would you connect the method invocation that changes the state of the object to a message sending process, and how should the notification Message be structured? @@ -17,16 +17,21 @@
Annotation-driven approach via @Publisher annotation - The annotation-driven approach allows you to annotate any method with the @Publisher annotation, specifying 'channel' attribute. - The Message will be constructed from the return value of method invocation and sent to a channel specified by 'channel' attribute. - To further manage message structure you can also use a combination of both @Payload and @Header annotations. + The annotation-driven approach allows you to annotate any method with the @Publisher annotation, + specifying a 'channel' attribute. + The Message will be constructed from the return value of the method invocation and sent to a channel specified by the 'channel' attribute. + To further manage message structure, you can also use a combination of both @Payload + and @Header annotations. - Internally message publishing feature of Spring Integration uses both Spring AOP by defining PublisherAnnotationAdvisor and - Spring 3.0 Expression Language (SpEL) support, giving you considerable flexibility and control over the structure of the Message it will build. + Internally this message publishing feature of Spring Integration uses both Spring AOP by defining + PublisherAnnotationAdvisor and + Spring 3.0's Expression Language (SpEL) support, giving you considerable flexibility and control over the structure of the + Message it will publish. - - PublisherAnnotationAdvisor defines and binds the following variables: + + + The PublisherAnnotationAdvisor defines and binds the following variables: #return - will bind to a return value allowing you to reference it or its @@ -44,7 +49,7 @@ - Let's look at couple of examples: + Let's look at a couple of examples: @Publisher @@ -59,7 +64,7 @@ public String defaultPayload(String fname, String lname) { Message payload - will be the return type and value of the method. This is the default. - A newly constructed message will be sent to a default publisher channel configured with annotation post processor (see the end of this section). + A newly constructed message will be sent to a default publisher channel configured with an annotation post processor (see the end of this section). @@ -70,10 +75,10 @@ public String defaultPayload(String fname, @Header("last") String lname) { } - In this example everything is the same as above, however we are not using default publishing channel. Instead we are specifying - the publishing channel via 'channel' attribute of @Publisher annotation. - We are also adding @Header annotation which results in the Message header with the name 'last' and the value of 'lname' input parameter - to be added to the newly constructed Message. + In this example everything is the same as above, except that we are not using a default publishing channel. Instead we are specifying + the publishing channel via the 'channel' attribute of the @Publisher annotation. + We are also adding a @Header annotation which results in the Message header named 'last' having the same value + as the 'lname' method parameter. That header will be added to the newly constructed Message. @@ -84,8 +89,8 @@ public String defaultPayloadButExplicitAnnotation(String fname, @Header String l } - The above example is almost identical to the previous one. The only difference here is that we are using @Payload annotation - on the method, thus explicitly specifying that the return value of the method should be used as a payload of the Message. + The above example is almost identical to the previous one. The only difference here is that we are using a @Payload annotation + on the method, thus explicitly specifying that the return value of the method should be used as the payload of the Message. @@ -96,9 +101,11 @@ public String setName(String fname, String lname, @Header("x") int num) { } - Here we are expending on the previous configuration by using Spring Expression language in the @Payload annotation further instructing - the framework on how the message should be constructed. In this particular case the message will be a concatenation of the return value of the method invocation and - 'lname' input argument. Message header 'x' with value of 'num' input argument will be added to the newly constructed Message. + Here we are expanding on the previous configuration by using the Spring Expression Language in the + @Payload annotation to further instruct + the framework how the message should be constructed. In this particular case the message will be a concatenation of the return + value of the method invocation and the 'lname' input argument. The Message header named 'x' will have its value determined by + the 'num' input argument. That header will be added to the newly constructed Message. @@ -108,29 +115,30 @@ public String argumentAsPayload(@Payload String fname, @Header String lname) { } - In the above example you see another usage of @Payload annotation. Here we are annotating method argument - which will become a payload of newly constructed message. + In the above example you see another usage of the @Payload annotation. Here we are annotating a method argument + which will become the payload of the newly constructed message. - As with most other annotation-driven features in Spring, you will need to register a post-processor (PublisherAnnotationBeanPostProcessor). <bean class="org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor"/> - You can also use namespace support for added convenience: + You can instead use namespace support for a more concise configuration: <si:annotation-config default-publisher-channel="defaultChannel"/> - Similar to other Spring annotations (e.g., @Controller), @Publisher is a meta-annotation, which means you can define your own annotations - that will be treated as @Publisher + Similar to other Spring annotations (@Component, @Scheduled, etc.), @Publisher can also be used as a meta-annotation. + That means you can define your own annotations + that will be treated in the same way as the @Publisher itself. -Here we defined @Audit annotation which itself is a @Publisher. Also note that you can define channel +Here we defined the @Audit annotation which itself is annotated with @Publisher. +Also note that you can define a channel attribute on the meta-annotation thus encapsulating the behavior of where messages will be sent inside of this annotation. Now you can annotate any method: @@ -139,10 +147,14 @@ public String test() {     return "foo"; }]]> -In the above example every invocation of test() method will result in Message with payload which is the return value of the method -invocation to be sent to auditChannel +In the above example every invocation of the test() method will result in a Message with a payload created from its return value. +Each Message will be sent to the channel named auditChannel. One of the benefits of this technique is that you can +avoid the duplication of the same channel name across multiple annotations. You also can provide a level of indirection between your own, +potentially domain-specific annotations and those provided by the framework. + -You can also annotate the class which would mean that the properties of this annotation will be applied on every public method of this class + +You can also annotate the class which would mean that the properties of this annotation will be applied on every public method of that class.
- XML-based approach via <publishing-interceptor> element + XML-based approach via the <publishing-interceptor> element The XML-based approach allows you to configure the same AOP-based Message Publishing functionality with simple namespace-based configuration of a MessagePublishingInterceptor. @@ -195,7 +207,7 @@ static class BankingOperationsImpl implements BankingOperations { ]]> - As you can see the <publishing-interceptor> configuration look rather similar to Annotation-based approach + As you can see the <publishing-interceptor> configuration looks rather similar to the Annotation-based approach, and it also utilizes the power of the Spring 3.0 Expression Language. @@ -203,11 +215,11 @@ static class BankingOperationsImpl implements BankingOperations { render a Message with the following structure: - The Message payload will be of type String and value of "Echoing: [value]" where value is the value + The Message payload will be of type String with the content "Echoing: [value]" where value is the value returned by an executed method. - The Message will have header with the key "foo" value "bar". + The Message will have a header with the name "foo" and value "bar". The Message will be sent to echoChannel. @@ -222,7 +234,7 @@ static class BankingOperationsImpl implements BankingOperations { The Message payload will be the same as in the above sample - The Message will have header with the key "foo" and value that is the result of the SpEL expression 'bar'.toUpperCase() . + The Message will have a header named "foo" whose value is the result of the SpEL expression 'bar'.toUpperCase() . The Message will be sent to echoChannel. @@ -257,23 +269,23 @@ static class BankingOperationsImpl implements BankingOperations { One important thing to understand is that publishing occurs in the same thread as your component's execution. So by default in is synchronous. - This means that the entire message flow would have to wait until he publisher flow completes.  - However, quite often you want the complete opposite and that is to use Message publishing feature to initiate asynchronous sub-flows. + This means that the entire message flow would have to wait until the publisher's flow completes.  + However, quite often you want the complete opposite and that is to use this Message publishing feature to initiate asynchronous sub-flows. For example, you might host a service (HTTP, WS etc.) which receives a remote request.You may want to send this request internally into a process that might take a while. However you may also want to reply to the user right away. So, instead of sending inbound - request for processing via the output channel (the conventional way), you can simply use ''outout-channel or $replyChannel'' header - to send simple acknowledgment-like reply back to the caller while using Message publisher feature to initiate a complex flow. + requests for processing via the output channel (the conventional way), you can simply use 'output-channel' or a 'replyChannel' header + to send a simple acknowledgment-like reply back to the caller while using the Message publisher feature to initiate a complex flow. EXAMPLE: Here is the simple service that receives a complex payload, which needs to be sent further for processing, but it - also need to reply to the caller with a simple acknowledgment. - - So instead of hooking up the complex flow to the output channel we use Message publishing feature instead configuring it to create a - new Message using the input argument of the service method (above) and sending it to the 'localProcessChannel'. And to make sure this sub-flow - is asynchronous all we need to do is make sure that we send it to any type of async channel (ExecutorChannel in this example). + So instead of hooking up the complex flow to the output channel we use the Message publishing feature instead. We configure it to create a + new Message using the input argument of the service method (above) and send that to the 'localProcessChannel'. And to make sure this sub-flow + is asynchronous all we need to do is send it to any type of asynchronous channel (ExecutorChannel in this example). @@ -291,10 +303,11 @@ static class BankingOperationsImpl implements BankingOperations { + ]]> - Another way of handling thi type of scenario is through wire-tap + Another way of handling this type of scenario is with a wire-tap.
@@ -302,10 +315,11 @@ static class BankingOperationsImpl implements BankingOperations { Producing and publishing messages based on a scheduled trigger In the above sections we looked at the Message publishing feature of Spring Integration which constructs and publishes messages as by-products of Method invocations. - However in that case, you are still responsible for invoking the method. + However in those cases, you are still responsible for invoking the method. In Spring Integration 2.0 we've added another related useful feature: support for scheduled Message producers/publishers via the new "expression" attribute on the 'inbound-channel-adapter' element. Scheduling could be based on several triggers, any one of which may be configured on the 'poller' sub-element. - Currently we support cron, fixed-rate, fixed-delay as well as any custom trigger implemented by you. + Currently we support cron, fixed-rate, fixed-delay as well as any custom trigger implemented by you and + referenced by the 'trigger' attribute value. As mentioned above, support for scheduled producers/publishers is provided via the <inbound-channel-adapter> xml element. @@ -320,7 +334,7 @@ static class BankingOperationsImpl implements BankingOperations { ]]>
In the above example an inbound Channel Adapter will be created which will construct a Message with its payload being the result of the expression  - defined in the expression attribute. Such message will be created and sent every time after the delay specified by the fixed-delay attribute. + defined in the expression attribute. Such messages will be created and sent every time the delay specified by the fixed-delay attribute occurs. cron attribute. - ]]> Here you can see that in a way very similar to the Message publishing feature we are enriching a newly constructed Message with - extra Message headers which could take scalar values as well as the results of evaluating Spring expressions. + extra Message headers which can take scalar values or the results of evaluating Spring expressions.