Message listener adapter adapter that delegates the handling of messages to target listener methods via refection, with flexible message tyep conversion. Allows listener methods to operate on message content types, completely independent from the Rabbit API.
By default, the content of incoming Rabbit messges gets extracted before being passed into the target listener method, to let the target method operate on message content tyeps such as String or byte array instead of the raw 'Message'. Message type conversion is delegated to a Spring AMQ 'MessageConverter'. Be default, a 'SimpleMessageConverter' will be used. (If you do not want such automatic message conversijon taking palce, then be sure to set the 'setMessageConverter MessageConverter' to 'null'.)
If a target listener method returns a non-null object (typically of a message content type such as String or byte array), it will get wrapped in a Rabbit 'Message' and sent to the exchange of the incoming message with the routingKey that comes from the Rabbit ReplyTo property or via 'setResponseRoutingKey(String) spicified routingKye').
Note: The sending of response messges is only available when using the 'ChannelAwareMessageListener' entry point (typically through a Spring message listener container). Usage as 'MessageListener' does 'not' support the generation of response messages.
Find below some examples of method signaures compliant with this adapter class. This first example handles all 'Message' types and gets passed the contents of each 'Message' type as an argument. No 'Message' will be sent back as all of these methods return 'void'.
public interface MessageContentsDelegate { void handleMessage(String text); void handleMessage(Map map); void handleMessage(byte[] bytes); void handleMessage(Serializable obj); }
This next example handle a 'Message' delegate that just consumes the 'String' contents of 'Message Messages'. Notice also how the name of the 'Message' handling method is different from the 'ORIGINAL_DEFAULT_LISTENER_METHOD original' (this will have to be configured in the attandant bean definition). Again, no 'Message' will be sent back as the method returns 'void'.
public interface TextMessageContentDelegate { void onMessage(String text); }
This final example illustrates a 'Message' delegate that just consumes the 'String' contents of 'Message Messages'. Notice how the return type of this method is 'String': This will result in the configured 'MessageListenerAdapter' sending a 'Message' in response.
public interface ResponsiveTextMessageContentDelegate { String handleMessage(String text); }
For further examples and discussion please do refer to the Spring reference documentation which describes. this class (and its attendant XML configuration) in detail.
开始解释坑爹的地方,众所周知,MessageListener接口为
public interface MessageListener { void onMessage(Message message); }
上面的the next example中也使用了onMessage方法,于是我以为可以直接写一个带有这个方法的pojo类让MessageListenerAdapter适配,结果很显然悲剧。注释中的“Notice also how the name of the 'Message' handling method is different from the 'ORIGINAL_DEFAULT_LISTENER_METHOD original' (this will have to be configured in the attandant bean definition).”开始没怎么明白,后来才知道“this will have to be configured in the attandant bean definition”告诉我们要使用onMessage方法,请修改Bean的配置,将ORIGINAL_DEFAULT_LISTENER_METHOD设置成'onMessage'!哎,为什么用onMessage这个容易浑淆的方法名作例子呢?
/** * Out-of-the-box value for the default listener method: "handleMessage". */ public static final String ORIGINAL_DEFAULT_LISTENER_METHOD = "handleMessage";
2011.3.14 12:47 更新
如果采用java-based的配置:
package asynchronous.consumer; import org.springframework.amqp.core.MessageListener; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ExampleAmqpConfiguration { @Autowired private ConnectionFactory connectionFactory; @Bean public SimpleMessageListenerContainer messageListenerContainer() { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.setQueueNames("myqueue"); container.setMessageListener(exampleListener()); return container; } @Bean public ExampleListener plainExampleListener() { ExampleListener exampleListener = new ExampleListener(); return exampleListener; } @Bean public MessageListener exampleListener() { MessageListener listener = new MessageListenerAdapter(plainExampleListener()); return listener; } }
将一个简单的POJO通过MessageListenerAdapter代理成MessageListener,在注入到SimpleMessageListenerContainer。
那么XML配置又是怎样的呢?截取一个配置片段:
<bean id="textMessageContentListener" class="stephansun.github.samples.amqp.spring.listeneradapter.TextMessageContentListener"/> <rabbit:listener-container connection-factory="connectionFactory"> <rabbit:listener ref="textMessageContentListener" queues="myqueue" method="handleMessage"/> </rabbit:listener-container>
可以看出XML配置文件不需要我们知道MessageListenerAdapter类,关键点在<rabbit:listener/>Element的method Node上,看注释:
Attribute : method The name of the listener method to invoke. If not specified, the target bean is supposed to implement the MessageListener or ChannelAwareMessageListener interface. Data Type : string
如果没有写method,Spring会认为你ref的Bean是一个实现了MessageListener和ChanelAwareMessage接口的类,这两个接口分别有onMessage(Message message)和onMessage(Message message, Channel channel)方法。只有写了method,Spring才会调用MessageListenerAdapter来适配你的POJO类,并默认将method对应的方法变成监听消息的处理方法。默认handleMessage,所以想使用XML配置文件,即使自己写的POJO也是MessageListenerAdapter中默认的适配的handleMessage方法,也是必须在在XML中写上method="handleMessage"。