Message Publishing feature will allow you to send a message as a result of method invocation. For example; Imagine you have a component and every time the state of this components changes you would like to get notified. The easiest way to send notification 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 what should be the structure of the message? Message Publishing feature will allow you to do just that.
Spring Integration provides two approaches - XML and Annotation.
Annotation bassed approach allows you to annotate any method with @Publisher
annotation and
provide configuration attributes which will dictate the structure of a Message. Invocation of such
method will be proxied through PublisherAnnotationAdvisor
which will
construct a Message and send it to a channel.
Internally PublisherAnnotationAdvisor
uses Spring 3.0 Expression Language support giving you
the flexibility and control over the structure of a Message it will build.
PublisherAnnotationAdvisor
defines and binds the following variables:
#return - will bind to a return value allowing you to reference it or its attributes (e.g., #return.foo where 'foo' is an attribute of the object bound to #return)
#exception - will bind to an exception if one is thrown.
#[parameName] - will be dynamically constructed pointing to the method parameter names (e.g., #fname as in the above method)
@Publisher(value="#return", channel="testChannel", headers="bar='123',fname=#fname") public String setName(String fname, String lname){ return fname + " " + lname; }
In the above example the Message will be constructed and its structure will be as follows:
Message payload - will be of type String and contain the value returned by the method.
Message headers will be 'bar' with value of "123" and 'fname' with value of 'fname' parameter of the method.
As with any other annotation you will need to register PublisherAnnotationBeanPostProcessor
<bean class="org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor"/>
XML-based approach allows you to configure Message Publishing via AOP-based configuration and
simple namespace-based configuration of MessagePublishingInterceptor
.
It certainly has certain benefits over annotation based approach since it
allows you to use AOP pointcut expressions, thus possibly intercepting multiple methods at once or
intercepting and publishing methods to which you don't have a source code.
To configure Message Publishing via XML all you need is the following two things:
Provide configuration for MessagePublishingInterceptor
via <publisher>
XML element
Provide AOP configuration to apply MessagePublishingInterceptor
<beans:bean id="testBean" class="org.foo.bar.TestBean" /> <aop:config> <aop:advisor advice-ref="interceptor" pointcut="bean(testBean)" /> </aop:config> <publisher id="interceptor" default-channel="defaultChannel"> <method pattern="echo" payload="'Echoing: ' + #return" headers="foo='bar'" channel="echoChannel"/> <method pattern="echoDef*" payload="#return"/> <method pattern="foo*"/> </publisher>
As you can see <publisher>
uses the same variables as
PublisherAnnotationAdvisor
to utilize the power of Spring 3.0 Expression Langage.
In the above example the execution of echo
method of a testBean
will
rander the Message with the following structure:
Message payload - will be of type String and value of "Echoing: [value]" where value
is the value
returned by an executed method.
Message headers will be 'foo' with value of "bar".
Message will be sent to echoChannel
.
In the second method mapping the execution of any method that begins with echoDef
of testBean
will result in the
Message with the following structure.
Message payload - will be the value returned by an executed method.
Since channel
attriute is not provided, the Message will be sent to the
defaultChannel
defined by the publisher.
The third mapping is almost identical to the previous (with the exceptipon of method pattern), since the return value will be mapped to the Message paylad by default if nothing else is specifued.
For a simple maping rules you can rely on publisher defaults. For example:
<publisher id="anotherInterceptor"/>
This will map the return value of every method that matches the pointcut expression to a payload and will be sent to a default-channel. If the defaultChannelis not specified (as above) the messages will be sent to nullChannel