Browse Source

Introduce acknowledgeAfterListener flag for custom acknowledge handling

Closes gh-34635
pull/34656/head
Juergen Hoeller 9 months ago
parent
commit
20736bd06f
  1. 17
      spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java
  2. 51
      spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java

17
spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -63,6 +63,9 @@ public abstract class AbstractJmsListenerContainerFactory<C extends AbstractMess
@Nullable @Nullable
private Integer sessionAcknowledgeMode; private Integer sessionAcknowledgeMode;
@Nullable
private Boolean acknowledgeAfterListener;
@Nullable @Nullable
private Boolean pubSubDomain; private Boolean pubSubDomain;
@ -141,6 +144,14 @@ public abstract class AbstractJmsListenerContainerFactory<C extends AbstractMess
this.sessionAcknowledgeMode = sessionAcknowledgeMode; this.sessionAcknowledgeMode = sessionAcknowledgeMode;
} }
/**
* @since 6.2.6
* @see AbstractMessageListenerContainer#setAcknowledgeAfterListener(boolean)
*/
public void setAcknowledgeAfterListener(Boolean acknowledgeAfterListener) {
this.acknowledgeAfterListener = acknowledgeAfterListener;
}
/** /**
* @see AbstractMessageListenerContainer#setPubSubDomain(boolean) * @see AbstractMessageListenerContainer#setPubSubDomain(boolean)
*/ */
@ -209,6 +220,7 @@ public abstract class AbstractJmsListenerContainerFactory<C extends AbstractMess
this.observationRegistry = observationRegistry; this.observationRegistry = observationRegistry;
} }
@Override @Override
public C createListenerContainer(JmsListenerEndpoint endpoint) { public C createListenerContainer(JmsListenerEndpoint endpoint) {
C instance = createContainerInstance(); C instance = createContainerInstance();
@ -234,6 +246,9 @@ public abstract class AbstractJmsListenerContainerFactory<C extends AbstractMess
if (this.sessionAcknowledgeMode != null) { if (this.sessionAcknowledgeMode != null) {
instance.setSessionAcknowledgeMode(this.sessionAcknowledgeMode); instance.setSessionAcknowledgeMode(this.sessionAcknowledgeMode);
} }
if (this.acknowledgeAfterListener != null) {
instance.setAcknowledgeAfterListener(this.acknowledgeAfterListener);
}
if (this.pubSubDomain != null) { if (this.pubSubDomain != null) {
instance.setPubSubDomain(this.pubSubDomain); instance.setPubSubDomain(this.pubSubDomain);
} }

51
spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -152,7 +152,8 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
implements MessageListenerContainer { implements MessageListenerContainer {
private static final boolean micrometerJakartaPresent = ClassUtils.isPresent( private static final boolean micrometerJakartaPresent = ClassUtils.isPresent(
"io.micrometer.jakarta9.instrument.jms.JmsInstrumentation", AbstractMessageListenerContainer.class.getClassLoader()); "io.micrometer.jakarta9.instrument.jms.JmsInstrumentation",
AbstractMessageListenerContainer.class.getClassLoader());
@Nullable @Nullable
private volatile Object destination; private volatile Object destination;
@ -170,14 +171,14 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
@Nullable @Nullable
private String subscriptionName; private String subscriptionName;
private boolean pubSubNoLocal = false;
@Nullable @Nullable
private Boolean replyPubSubDomain; private Boolean replyPubSubDomain;
@Nullable @Nullable
private QosSettings replyQosSettings; private QosSettings replyQosSettings;
private boolean pubSubNoLocal = false;
@Nullable @Nullable
private MessageConverter messageConverter; private MessageConverter messageConverter;
@ -190,6 +191,8 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
@Nullable @Nullable
private ObservationRegistry observationRegistry; private ObservationRegistry observationRegistry;
private boolean acknowledgeAfterListener = true;
private boolean exposeListenerSession = true; private boolean exposeListenerSession = true;
private boolean acceptMessagesWhileStopping = false; private boolean acceptMessagesWhileStopping = false;
@ -500,12 +503,7 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
*/ */
@Override @Override
public boolean isReplyPubSubDomain() { public boolean isReplyPubSubDomain() {
if (this.replyPubSubDomain != null) { return (this.replyPubSubDomain != null ? this.replyPubSubDomain : isPubSubDomain());
return this.replyPubSubDomain;
}
else {
return isPubSubDomain();
}
} }
/** /**
@ -596,6 +594,37 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
return this.observationRegistry; return this.observationRegistry;
} }
/**
* Specify whether the listener container should automatically acknowledge
* each JMS Message after the message listener returned. This applies in
* case of client acknowledge modes, including vendor-specific modes but
* not in case of auto-acknowledge or a transacted JMS Session.
* <p>As of 6.2, the default is {@code true}: The listener container will
* acknowledge each JMS Message even in case of a vendor-specific mode,
* assuming client-acknowledge style processing for custom vendor modes.
* <p>If the provided listener prefers to manually acknowledge each message in
* the listener itself, in combination with an "individual acknowledge" mode,
* switch this flag to {code false} along with the vendor-specific mode.
* @since 6.2.6
* @see #setSessionAcknowledgeMode
* @see #setMessageListener
* @see Message#acknowledge()
*/
public void setAcknowledgeAfterListener(boolean acknowledgeAfterListener) {
this.acknowledgeAfterListener = acknowledgeAfterListener;
}
/**
* Determine whether the listener container should automatically acknowledge
* each JMS Message after the message listener returned.
* @since 6.2.6
* @see #setAcknowledgeAfterListener
* @see #isClientAcknowledge(Session)
*/
public boolean isAcknowledgeAfterListener() {
return this.acknowledgeAfterListener;
}
/** /**
* Set whether to expose the listener JMS Session to a registered * Set whether to expose the listener JMS Session to a registered
* {@link SessionAwareMessageListener} as well as to * {@link SessionAwareMessageListener} as well as to
@ -833,7 +862,7 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
JmsUtils.commitIfNecessary(session); JmsUtils.commitIfNecessary(session);
} }
} }
else if (message != null && isClientAcknowledge(session)) { else if (message != null && isAcknowledgeAfterListener() && isClientAcknowledge(session)) {
message.acknowledge(); message.acknowledge();
} }
} }

Loading…
Cancel
Save