I have an application which is built on Spring 3.0.5 and uses JMS for exchanging messages. The beans which receive the messages are configured by using the jms
namespace. The class looks like this
class MyService {
public void receive(String msg) {
...
}
}
The Spring configuration looks like this
<jms:listener-container dest开发者_Python百科ination-type="queue">
<jms:listener destination="queue.test" ref="myService" method="receive"/>
</jms:listener-container>
However, when I change the receive method to get a Message
object the method is no longer called.
class MyService {
public void receive(TextMessage msg) {
...
}
}
I realize that I could just use the MessageListenerAdapter
but it is more configuration overhead and I am just wondering why this doesn't work.
Any insight is greatly appreciated.
Frank
The <jms:listener>
config automatically creates a MessageListenerAdapter
for you, so it's not necesarry for you to configure that explicitly.
Your problem is that MessageListenerAdapter
is designed to decouple your code from the JMS API altogether. The target method in <jms:listener>
must declare one of the parameter types permitted by MessageListenerAdapter
(see docs), which represent the possible payload types of a message, i.e. one of String
, Serializable
, byte[]
or Map
.
If you want to receive the raw JMS TextMessage
object, then your listener class has to implement MessageListener
or SessionAwareMessageListener
. That makes it a "proper" JMS listener. In that case, the method
config becomes redundant, and you can just use :
<jms:listener destination="queue.test" ref="myService"/>
I'm actually rather surprised that Spring didn't throw an exception when it found that your receive
method had an invalid parameter type.
What I've figured out is that in order for the MessageListenerAdapter
not to convert the message the messageConverter
attribute must be set to null
. However, when using the namespace configuration it is not possible to disable the default message converter that is automatically created.
The code in the AbstractListenerContainerParser
checks if the message-converter
attribute of the <jms:listener-container>
is either not set or points to a valid bean. Otherwise a SimpleMessageAdapter
is instantiated.
To work around this problem I've created a NoopMessageConverter
which solves the problem
public class NoopMessageConverter implements MessageConverter {
@Override
public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {
return (Message) object;
}
@Override
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {
return message;
}
}
Then configure the <jms:listener-container>
like this
<bean id="noopMessageConverter" class="NoopMessageConverter"/>
<jms:listener-container message-converter="noopMessageConverter">
<jms:listener destination="queue.test" ref="myService" method="receive"/>
</jms:listener-container>
Then you can create your bean as follows and the receive
method is called
class MyService {
public void receive(TextMessage msg) {
...
}
}
精彩评论