即使消息是由MessageListener接收的,我也不想从队列中删除,我想在onMessage方法中进行一些处理并根据结果:
我希望commit();
获得成功 - 因此消息将从队列中完全删除。
对于失败 - 不提交 - rollback();
以便重新传递消息(默认情况下有时),然后转到死信队列(DLQ)。这对我们来说没问题。
我使用:SpringBoot和hornetq(spring-boot-starter-hornetq-1.4.7.RELEASE)。 设定:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
import org.springframework.jndi.JndiObjectFactoryBean;
import org.springframework.jndi.JndiTemplate;
import javax.jms.ConnectionFactory;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.Properties;
import static com.test.hornetq.Receiver.LOG;
import static javax.jms.Session.SESSION_TRANSACTED;
@Configuration
public class JmsConfig {
private String host;
private String port;
private String connectionFactoryJndiName;
private String jndiInit;
private String user;
private String password;
private String jmsReceiverConcurrency;
public JmsConfig(final Environment env) {
host = env.getProperty("host");
port = env.getProperty("port");
connectionFactoryJndiName = env.getProperty("connectionfactory.jndiname");
jndiInit = env.getProperty("jndiInit");
user = env.getProperty("user");
password = env.getProperty("password");
jmsReceiverConcurrency = env.getProperty("jmsReceiverConcurrency");
}
@Bean
public JndiTemplate jndiTemplate() {
final JndiTemplate jndiTemplate = new JndiTemplate();
jndiTemplate.setEnvironment(getProperties());
return jndiTemplate;
}
@Bean
public JndiObjectFactoryBean jmsConnectionFactory() throws NamingException {
final JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiTemplate(jndiTemplate());
jndiObjectFactoryBean.setJndiName(connectionFactoryJndiName);
jndiObjectFactoryBean.afterPropertiesSet();
return jndiObjectFactoryBean;
}
@Bean
@Primary
public ConnectionFactory connectionFactory() throws NamingException {
final UserCredentialsConnectionFactoryAdapter adapter = new UserCredentialsConnectionFactoryAdapter();
adapter.setTargetConnectionFactory((ConnectionFactory) jmsConnectionFactory().getObject());
adapter.setUsername(user);
adapter.setPassword(password);
return adapter;
}
@Bean
public JmsListenerContainerFactory<?> myJmsContainerFactory() throws NamingException {
final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setSubscriptionDurable(false);
factory.setConcurrency(jmsReceiverConcurrency);
factory.setMaxMessagesPerTask(1);
factory.setSessionTransacted(true);
factory.setSessionAcknowledgeMode(SESSION_TRANSACTED);
factory.setErrorHandler(t -> {
LOG.error("Error in listener!", t);
});
return factory;
}
private Properties getProperties() {
final Properties jndiProps = new Properties();
jndiProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, jndiInit);
jndiProps.setProperty(Context.PROVIDER_URL, "http-remoting://" + host + ":" + port);
jndiProps.setProperty(Context.SECURITY_PRINCIPAL, user);
jndiProps.setProperty(Context.SECURITY_CREDENTIALS, password);
return jndiProps;
}
}
接收者:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Session;
@Component
public class Receiver {
@JmsListener(destination = "${destination.name}", containerFactory = "myJmsContainerFactory")
public void onReceive(final MapMessage message, Session session) throws JMSException {
try {
System.out.println(">>>> " + message);
session.rollback();
} catch (Exception ex) {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>THROW ");
throw ex;
}
}
}
但是当我做rollback();
时,没有任何事情发生,信息也没有回来。
答案 0 :(得分:0)
代码工作。问题出在服务器端的hornetq设置中。
<pre-acknowledge>true</pre-acknowledge>
请注意,如果您使用预先确认模式,那么您将丢失正在使用的消息的事务语义,因为显然它们首先在服务器上被确认,而不是在您提交事务时。这可能是显而易见的,但我们希望明确这些事情以避免混淆!