📄 messagelisteneradapter.java
字号:
/**
* Spring {@link SessionAwareMessageListener} entry point.
* <p>Delegates the message to the target listener method, with appropriate
* conversion of the message argument. If the target method returns a
* non-null object, wrap in a JMS message and send it back.
* @param message the incoming JMS message
* @param session the JMS session to operate on
* @throws JMSException if thrown by JMS API methods
*/
public void onMessage(Message message, Session session) throws JMSException {
Object convertedMessage = extractMessage(message);
String methodName = getListenerMethodName(message, convertedMessage);
if (methodName == null) {
Object delegate = getDelegate();
if (delegate != this) {
if (delegate instanceof SessionAwareMessageListener) {
if (session != null) {
((SessionAwareMessageListener) delegate).onMessage(message, session);
return;
}
else if (!(delegate instanceof MessageListener)) {
throw new javax.jms.IllegalStateException("MessageListenerAdapter cannot handle a " +
"SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
}
}
if (delegate instanceof MessageListener) {
((MessageListener) delegate).onMessage(message);
return;
}
}
throw new javax.jms.IllegalStateException("No default listener method specified: " +
"Either specify a non-null value for the 'defaultListenerMethod' property or " +
"override the 'getListenerMethodName' method.");
}
Object[] listenerArguments = buildListenerArguments(convertedMessage);
Object result = invokeListenerMethod(methodName, listenerArguments);
if (result != null) {
handleResult(result, message, session);
}
else {
logger.debug("No result object given - no result to handle");
}
}
/**
* Initialize the default implementations for the adapter's strategies.
* @see #setMessageConverter
* @see org.springframework.jms.support.converter.SimpleMessageConverter
*/
protected void initDefaultStrategies() {
setMessageConverter(new SimpleMessageConverter());
}
/**
* Handle the given exception that arose during listener execution.
* The default implementation logs the exception at error level.
* <p>This method only applies when used as standard JMS {@link MessageListener}.
* In case of the Spring {@link SessionAwareMessageListener} mechanism,
* exceptions get handled by the caller instead.
* @param ex the exception to handle
* @see #onMessage(javax.jms.Message)
*/
protected void handleListenerException(Throwable ex) {
logger.error("Listener execution failed", ex);
}
/**
* Extract the message body from the given JMS message.
* @param message the JMS <code>Message</code>
* @return the content of the message, to be passed into the
* listener method as argument
* @throws JMSException if thrown by JMS API methods
*/
protected Object extractMessage(Message message) throws JMSException {
MessageConverter converter = getMessageConverter();
if (converter != null) {
return converter.fromMessage(message);
}
return message;
}
/**
* Determine the name of the listener method that is supposed to
* handle the given message.
* <p>The default implementation simply returns the configured
* default listener method, if any.
* @param originalMessage the JMS request message
* @param extractedMessage the converted JMS request message,
* to be passed into the listener method as argument
* @return the name of the listener method (never <code>null</code>)
* @throws JMSException if thrown by JMS API methods
* @see #setDefaultListenerMethod
*/
protected String getListenerMethodName(Message originalMessage, Object extractedMessage) throws JMSException {
return getDefaultListenerMethod();
}
/**
* Build an array of arguments to be passed into the target listener method.
* Allows for multiple method arguments to be built from a single message object.
* <p>The default implementation builds an array with the given message object
* as sole element. This means that the extracted message will always be passed
* into a <i>single</i> method argument, even if it is an array, with the target
* method having a corresponding single argument of the array's type declared.
* <p>This can be overridden to treat special message content such as arrays
* differently, for example passing in each element of the message array
* as distinct method argument.
* @param extractedMessage the content of the message
* @return the array of arguments to be passed into the
* listener method (each element of the array corresponding
* to a distinct method argument)
*/
protected Object[] buildListenerArguments(Object extractedMessage) {
return new Object[] {extractedMessage};
}
/**
* Invoke the specified listener method.
* @param methodName the name of the listener method
* @param arguments the message arguments to be passed in
* @return the result returned from the listener method
* @throws JMSException if thrown by JMS API methods
* @see #getListenerMethodName
* @see #buildListenerArguments
*/
protected Object invokeListenerMethod(String methodName, Object[] arguments) throws JMSException {
try {
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.setTargetObject(getDelegate());
methodInvoker.setTargetMethod(methodName);
methodInvoker.setArguments(arguments);
methodInvoker.prepare();
return methodInvoker.invoke();
}
catch (InvocationTargetException ex) {
throw new ListenerExecutionFailedException(
"Listener method '" + methodName + "' threw exception", ex.getTargetException());
}
catch (Throwable ex) {
throw new ListenerExecutionFailedException("Failed to invoke target method '" + methodName +
"' with arguments " + ObjectUtils.nullSafeToString(arguments), ex);
}
}
/**
* Handle the given result object returned from the listener method,
* sending a response message back.
* @param result the result object to handle (never <code>null</code>)
* @param request the original request message
* @param session the JMS Session to operate on (may be <code>null</code>)
* @throws JMSException if thrown by JMS API methods
* @see #buildMessage
* @see #postProcessResponse
* @see #getResponseDestination
* @see #sendResponse
*/
protected void handleResult(Object result, Message request, Session session) throws JMSException {
if (session != null) {
if (logger.isDebugEnabled()) {
logger.debug("Listener method returned result [" + result +
"] - generating response message for it");
}
Message response = buildMessage(session, result);
postProcessResponse(request, response);
Destination destination = getResponseDestination(request, response, session);
sendResponse(session, destination, response);
}
else {
if (logger.isWarnEnabled()) {
logger.warn("Listener method returned result [" + result +
"]: not generating response message for it because of no JMS Session given");
}
}
}
/**
* Build a JMS message to be sent as response based on the given result object.
* @param session the JMS Session to operate on
* @param result the content of the message, as returned from the listener method
* @return the JMS <code>Message</code> (never <code>null</code>)
* @throws JMSException if thrown by JMS API methods
* @see #setMessageConverter
*/
protected Message buildMessage(Session session, Object result) throws JMSException {
MessageConverter converter = getMessageConverter();
if (converter != null) {
return converter.toMessage(result, session);
}
else {
if (!(result instanceof Message)) {
throw new MessageConversionException(
"No MessageConverter specified - cannot handle message [" + result + "]");
}
return (Message) result;
}
}
/**
* Post-process the given response message before it will be sent.
* <p>The default implementation sets the response's correlation id
* to the request message's correlation id.
* @param request the original incoming JMS message
* @param response the outgoing JMS message about to be sent
* @throws JMSException if thrown by JMS API methods
* @see javax.jms.Message#setJMSCorrelationID
*/
protected void postProcessResponse(Message request, Message response) throws JMSException {
response.setJMSCorrelationID(request.getJMSCorrelationID());
}
/**
* Determine a response destination for the given message.
* <p>The default implementation first checks the JMS Reply-To
* {@link Destination} of the supplied request; if that is not <code>null</code>
* it is returned; if it is <code>null</code>, then the configured
* {@link #resolveDefaultResponseDestination default response destination}
* is returned; if this too is <code>null</code>, then an
* {@link InvalidDestinationException} is thrown.
* @param request the original incoming JMS message
* @param response the outgoing JMS message about to be sent
* @param session the JMS Session to operate on
* @return the response destination (never <code>null</code>)
* @throws JMSException if thrown by JMS API methods
* @throws InvalidDestinationException if no {@link Destination} can be determined
* @see #setDefaultResponseDestination
* @see javax.jms.Message#getJMSReplyTo()
*/
protected Destination getResponseDestination(Message request, Message response, Session session)
throws JMSException {
Destination replyTo = request.getJMSReplyTo();
if (replyTo == null) {
replyTo = resolveDefaultResponseDestination(session);
if (replyTo == null) {
throw new InvalidDestinationException("Cannot determine response destination: " +
"Request message does not contain reply-to destination, and no default response destination set.");
}
}
return replyTo;
}
/**
* Resolve the default response destination into a JMS {@link Destination}, using this
* accessor's {@link DestinationResolver} in case of a destination name.
* @return the located {@link Destination}
* @throws javax.jms.JMSException if resolution failed
* @see #setDefaultResponseDestination
* @see #setDefaultResponseQueueName
* @see #setDefaultResponseTopicName
* @see #setDestinationResolver
*/
protected Destination resolveDefaultResponseDestination(Session session) throws JMSException {
if (this.defaultResponseDestination instanceof Destination) {
return (Destination) this.defaultResponseDestination;
}
if (this.defaultResponseDestination instanceof DestinationNameHolder) {
DestinationNameHolder nameHolder = (DestinationNameHolder) this.defaultResponseDestination;
return getDestinationResolver().resolveDestinationName(session, nameHolder.name, nameHolder.isTopic);
}
return null;
}
/**
* Send the given response message to the given destination.
* @param response the JMS message to send
* @param destination the JMS destination to send to
* @param session the JMS session to operate on
* @throws JMSException if thrown by JMS API methods
* @see #postProcessProducer
* @see javax.jms.Session#createProducer
* @see javax.jms.MessageProducer#send
*/
protected void sendResponse(Session session, Destination destination, Message response) throws JMSException {
MessageProducer producer = session.createProducer(destination);
try {
postProcessProducer(producer, response);
producer.send(response);
}
finally {
JmsUtils.closeMessageProducer(producer);
}
}
/**
* Post-process the given message producer before using it to send the response.
* <p>The default implementation is empty.
* @param producer the JMS message producer that will be used to send the message
* @param response the outgoing JMS message about to be sent
* @throws JMSException if thrown by JMS API methods
*/
protected void postProcessProducer(MessageProducer producer, Message response) throws JMSException {
}
/**
* Internal class combining a destination name
* and its target destination type (queue or topic).
*/
private static class DestinationNameHolder {
public final String name;
public final boolean isTopic;
public DestinationNameHolder(String name, boolean isTopic) {
this.name = name;
this.isTopic = isTopic;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -