In addition to the XML namespace support for configuring Message Endpoints, it is also possible to use
annotations. The class-level @MessageEndpoint
annotation indicates that the
annotated class is capable of being registered as an endpoint, and the method-level
@Handler
annotation indicates that the annotated method is capable of handling
a message.
@MessageEndpoint(input="fooChannel") public class FooService { @Handler public void processMessage(Message message) { ... } }
In most cases, the annotated handler method should not require the Message
type as its
parameter. Instead, the method parameter type can match the message's payload type.
@MessageEndpoint(input="fooChannel")
public class FooService {
@Handler
public void processFoo(Foo foo) {
...
}
}
As described in the previous section, when the handler method returns a non-null value, the endpoint will
attempt to send a reply. This is consistent across both configuration options (namespace and annotations) in that
the message header's 'replyChannelName' property will be used if available, and the endpoint's default output is
the fallback. To configure the default output for an annotation-driven endpoint, provide the 'defaultOutput'
attribute on the @MessageEndpoint
.
@MessageEndpoint(input="exampleChannel", defaultOutput="replyChannel")
Finally, just as the 'schedule' sub-element and its 'period' attribute can be provided for a namespace-based
endpoint, the 'pollPeriod' attribute can be provided on the @MessageEndpoint
.
@MessageEndpoint(input="exampleChannel", pollPeriod=3000)
Two additional annotations are supported, and both act as a special form of handler method:
@Router
and @Splitter
. As with the
@Handler
annotation, methods annotated with either of these two annotations can
either accept the Message
itself or the message payload type as the parameter.
When using the @Router
annotation, the annotated method can return either the
MessageChannel
or String
type. In the case of the latter,
the endpoint will resolve the channel name as it does for the default output. Additionally, the method can return
either a single value or a collection. When a collection is returned, the reply message will be sent to multiple
channels. To summarize, the following method signatures are all valid.
@Router public MessageChannel route(Message message) {...} @Router public List<MessageChannel> route(Message message) {...} @Router public String route(Foo payload) {...} @Router public List<String> route(Foo payload) {...}
In addition to payload-based routing, a common requirement is to route based on metadata available within the
message header as either a property or attribute. Rather than requiring use of the
Message
type as the method parameter, the @Router
annotation may also map to either a property or attribute name.
@Router(property="customerType") public String route(String customerType) @Router(attribute="orderStatus") public List<String> route(OrderStatus status)
The @Splitter
annotation is also applicable to methods that expect either the
Message
type or the message payload type, and the return values of the method
should be a collection of any type. If the returned values are not actual Message
objects, then each of them will be sent as the payload of a message. The @Splitter
annotation expects a 'channel' attribute that specifies the channel name to which those messages should be sent.
@Splitter(channel="exampleChannel") List<LineItem> extractItems(Order order) { return order.getItems() }
The @Publisher
annotation is a convenience for sending messages with AOP
after-returning advice. For example, each time the following method is invoked, its return
value will be sent to the "fooChannel":
@Publisher(channel="fooChannel") public String foo() { return "bar"; }
Similarly, the @Subscriber
annotation triggers the retrieval of messages from a
channel, and the payload of each message will then be sent as input to an arbitrary method. This is one of the
simplest ways to configure asynchronous, event-driven behavior:
@Subscriber(channel="fooChannel") public void log(String foo) { System.out.println(foo); }