Spring integration 从MesageHandler引发的异常未返回消息

Spring integration 从MesageHandler引发的异常未返回消息,spring-integration,spring-jms,Spring Integration,Spring Jms,我们的应用程序有一个MessageHandler的实现,预期它将处理来自队列的消息。在不同的环境中,我们连接到不同的队列(GCP PubSub/AMQ) 使用GCP PubSub,当从MessageHandler#handleMessage(org.springfranework.messaging)引发异常时,消息将返回到PubSub。 而AMQ却没有发生同样的事情 而MessageHandler实例只是在带有ServiceActivator注释的方法上返回的。i、 例如,它没有显式地映射到其

我们的应用程序有一个
MessageHandler
的实现,预期它将处理来自队列的消息。在不同的环境中,我们连接到不同的队列(GCP PubSub/AMQ)

使用GCP PubSub,当从
MessageHandler#handleMessage
org.springfranework.messaging
)引发异常时,消息将返回到PubSub。 而AMQ却没有发生同样的事情

MessageHandler
实例只是在带有
ServiceActivator
注释的方法上返回的。i、 例如,它没有显式地映射到其他任何东西

我们为AMQ提供的简化配置如下:

配置创建JMSEndpoint:

private JmsMessageDrivenEndpoint jmsMessageDrivenEndpoint(@Autowired MessageChannel inputChannel) {

    ConnectionFactory connectionFactory= new JmsConnectionFactory(username, password, url);

    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setDestinationName("my-subscription");
    
    ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
    JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container, listener);
    endpoint.setOutputChannel(inputChannel);
    return endpoint;
}
 @Bean
  public MessageChannel myChannel() {
    return new DirectChannel();
  }
  @Bean
  @ServiceActivator(inputChannel = "myChannel")
  public MessageHandler engagementRegistration() {
    return new CustomHandler();
  }
class CustomHandler implements MessageHandler<?>
 {
 public void handleMessage(Message<?> message) {
 // logic to handle the message and throw MessageException(message)
 // When I have to send back the message
 }
 }
频道的配置:

private JmsMessageDrivenEndpoint jmsMessageDrivenEndpoint(@Autowired MessageChannel inputChannel) {

    ConnectionFactory connectionFactory= new JmsConnectionFactory(username, password, url);

    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setDestinationName("my-subscription");
    
    ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
    JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container, listener);
    endpoint.setOutputChannel(inputChannel);
    return endpoint;
}
 @Bean
  public MessageChannel myChannel() {
    return new DirectChannel();
  }
  @Bean
  @ServiceActivator(inputChannel = "myChannel")
  public MessageHandler engagementRegistration() {
    return new CustomHandler();
  }
class CustomHandler implements MessageHandler<?>
 {
 public void handleMessage(Message<?> message) {
 // logic to handle the message and throw MessageException(message)
 // When I have to send back the message
 }
 }
MessageHandler的ServiceActivator:

private JmsMessageDrivenEndpoint jmsMessageDrivenEndpoint(@Autowired MessageChannel inputChannel) {

    ConnectionFactory connectionFactory= new JmsConnectionFactory(username, password, url);

    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setDestinationName("my-subscription");
    
    ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
    JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container, listener);
    endpoint.setOutputChannel(inputChannel);
    return endpoint;
}
 @Bean
  public MessageChannel myChannel() {
    return new DirectChannel();
  }
  @Bean
  @ServiceActivator(inputChannel = "myChannel")
  public MessageHandler engagementRegistration() {
    return new CustomHandler();
  }
class CustomHandler implements MessageHandler<?>
 {
 public void handleMessage(Message<?> message) {
 // logic to handle the message and throw MessageException(message)
 // When I have to send back the message
 }
 }
简化的自定义处理程序:

private JmsMessageDrivenEndpoint jmsMessageDrivenEndpoint(@Autowired MessageChannel inputChannel) {

    ConnectionFactory connectionFactory= new JmsConnectionFactory(username, password, url);

    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setDestinationName("my-subscription");
    
    ChannelPublishingJmsMessageListener listener = new ChannelPublishingJmsMessageListener();
    JmsMessageDrivenEndpoint endpoint = new JmsMessageDrivenEndpoint(container, listener);
    endpoint.setOutputChannel(inputChannel);
    return endpoint;
}
 @Bean
  public MessageChannel myChannel() {
    return new DirectChannel();
  }
  @Bean
  @ServiceActivator(inputChannel = "myChannel")
  public MessageHandler engagementRegistration() {
    return new CustomHandler();
  }
class CustomHandler implements MessageHandler<?>
 {
 public void handleMessage(Message<?> message) {
 // logic to handle the message and throw MessageException(message)
 // When I have to send back the message
 }
 }
类CustomHandler实现MessageHandler
{
公共无效handleMessage(消息消息){
//处理消息和抛出MessageException(消息)的逻辑
//当我必须发回信息的时候
}
}

如果能在这件事上看到一些配置,那就太好了

您的GCP PubSub可能未配置为自动确认(或类似名称)。或者它是自动确认,但已经在整个过程将控制权返回给GCP使用者之后

不清楚AMQ是什么,但它可能会在消息到达消费者时自动确认消息,并且不会等待过程完成

更新

所以,您的AMQ就是关于JMS的

正如我所说,在异常之前,您有一个自动确认。 请参阅
JmsAccessor.sessionackknowledgemode
。这是一个
会话。自动确认
。现在看看它的JavaDocs:

/** With this acknowledgment mode, the session automatically acknowledges
  * a client's receipt of a message either when the session has successfully 
  * returned from a call to {@code receive} or when the message 
  * listener the session has called to process the message successfully 
  * returns.
  */ 

static final int AUTO_ACKNOWLEDGE = 1;
考虑在该
SimpleMessageListenerContainer
上将此配置为
true

/**
 * Set the transaction mode that is used when creating a JMS {@link Session}.
 * Default is "false".
 * <p>Note that within a JTA transaction, the parameters passed to
 * {@code create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)}
 * method are not taken into account. Depending on the Java EE transaction context,
 * the container makes its own decisions on these values. Analogously, these
 * parameters are not taken into account within a locally managed transaction
 * either, since the accessor operates on an existing JMS Session in this case.
 * <p>Setting this flag to "true" will use a short local JMS transaction
 * when running outside of a managed transaction, and a synchronized local
 * JMS transaction in case of a managed transaction (other than an XA
 * transaction) being present. This has the effect of a local JMS
 * transaction being managed alongside the main transaction (which might
 * be a native JDBC transaction), with the JMS transaction committing
 * right after the main transaction.
 * @see javax.jms.Connection#createSession(boolean, int)
 */
public void setSessionTransacted(boolean sessionTransacted) {
/**
*设置创建JMS{@link Session}时使用的事务模式。
*默认值为“false”。
*注意,在JTA事务中,传递给
*{@code创建(队列/主题)会话(布尔事务,int-ackknowledgeMode)}
*方法没有考虑在内。根据Java EE事务上下文,
*容器对这些值做出自己的决定。类似地,这些
*在本地管理的事务中不考虑参数
*或者,因为在本例中,访问器在现有JMS会话上操作。
*将此标志设置为“true”将使用短本地JMS事务
*在托管事务外部运行时,以及同步本地
*托管事务(XA除外)情况下的JMS事务
*(交易)存在。这具有本地JMS的效果
*与主事务一起管理的事务(可能是
*是本机JDBC事务),JMS事务正在提交
*就在主交易之后。
*@see javax.jms.Connection#createSession(boolean,int)
*/
public void SetSessionTransact(布尔sessionTransact){

为AMQ添加了相关配置的简化版本。请参阅我的答案中的更新。感谢您的回答。顺便说一句,这些bean都是独立的方法,只是为了简单起见将其组合在一起。SetSessionTransact似乎不起作用。而将sessionAcknowledgeMode设置为CLIENT_ACKNOWLEDGE起作用。您可以更新您的答案ac诚然。但使用
CLIENT_ACKNOWLEDGE
时,您必须手动确认消息。当您收到异常时,它确实不会被确认,但同时当您没有收到异常时,它也不会被确认,您也不会将其称为
javax.jms.message#ACKNOWLEDGE()
您自己。ActiveMQ中可能有一些选项使您的消息过早地被确认。。。