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中可能有一些选项使您的消息过早地被确认。。。