Spring 的缓存连接工厂。为什么我们需要关闭会话,尽管它们是要缓存的?

Spring's CachingConnectionFactory. Why do we need to close sessions although they are to be cached?

我正在努力了解 Spring CachingConnectionFactory

ActiveMQ documentation 建议在使用 JmsTemplate 时使用 Spring CachingConnectionFactory 或 ActiveMQ PooledConnectionFactory 作为连接工厂实现。

我理解这一点,因为使用正常的 ConnectionFactory 创建连接,启动会话,并且在每次调用 jmsTemplate.send() 时都关闭,这非常浪费。

所以我正在尝试实现一个带有 CachingConnectionFactory 的自定义 JmsTemplate bean,用于我可能有很多请求的地方 A) 持久化到 DB B) 排队 JMS。

@Configuration
public class JMSConfig {
    
    @Autowired
    private CachingConnectionFactory cachingConnectionFactory;

    @Bean
    @Qualifier("jmsTemplateCached")
    public JmsTemplate jmsTemplateCachingConnectionFactory() {
        cachingConnectionFactory.setSessionCacheSize(10);
        
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);
        jmsTemplate.setSessionAcknowledgeMode(JmsProperties.AcknowledgeMode.CLIENT.getMode());
        jmsTemplate.setSessionTransacted(true);
        jmsTemplate.setDeliveryPersistent(true);
        jmsTemplate.setConnectionFactory(cachingConnectionFactory);
        return jmsTemplate;
    }
}

我的第一个问题是关于 Spring Docs For CachngConnecionFactory 的:

SingleConnectionFactory subclass that adds Session caching as well MessageProducer caching. This ConnectionFactory also switches the "reconnectOnException" property to "true" by default, allowing for automatic recovery of the underlying Connection. By default, only one single Session will be cached, with further requested Sessions being created and disposed on demand. Consider raising the "sessionCacheSize" value in case of a high-concurrency environment.

但随后以粗体显示:

NOTE: This ConnectionFactory requires explicit closing of all Sessions obtained from its shared Connection. This is the usual recommendation for native JMS access code anyway. However, with this ConnectionFactory, its use is mandatory in order to actually allow for Session reuse.

这是否意味着如果我通过模板或我的 CachingConnectionFactory bean“手动”创建连接,我只需要关闭会话?换句话说:

    Connection connection = jmsTemplateCached.getConnectionFactory().createConnection();

    Session sess = connection.createSession(true, JmsProperties.AcknowledgeMode.CLIENT.getMode());

    MessageProducer producer = sess.createProducer(activeMQQueue);

    try {
        producer.send(activeMQQueue, new ActiveMQTextMessage());
        sess.commit();
    } catch (JMSException e) {
        sess.rollback();
    } finally {
        sess.close();
    }

如果我使用如下模板,我应该关闭还是不关闭会话?

    @Autowired
    public JmsTemplate jmsTemplateCached;

    @Transactional
    public InboundResponse peristAndEnqueueForProcessing(MitelInboundForm mitelInboundForm) throws IrresolvableException, JsonProcessingException, JMSException {

    //Removed for clarity, an entity has been persisted and is then to be enqueued via JMS.

        log.debug("Queue For Processing : {}", persistedRequest);

        String serialisedMessage = objectMapper.writeValueAsString(persistedRequest);
        ActiveMQTextMessage activeMQTextMessage = new ActiveMQTextMessage();
        activeMQTextMessage.setText(serialisedMessage);

        //Will throw JMS Exception on failure
        Session sessionUsed = jmsTemplateCached.execute((session, messageProducer) -> {
            messageProducer.send(activeMQQueue, activeMQTextMessage);
            session.commit();
            return session;
        });

        return response;
    }

其次,如果上面的jmsTemplate.execute()抛出异常,session会发生什么?它会在 x 次后回滚吗?

JmsTemplate 会在每次操作后可靠地关闭其资源(return 将会话写入缓存),包括 execute()

该评论与直接使用会话的用户代码有关;关闭操作被拦截并用于 return 缓存会话,而不是实际关闭它。您必须调用关闭,否则会话将被孤立。

是的,如果 sessionTransacted 为真,事务将(立即)回滚。

您不应调用提交 - 模板将在执行正常退出时执行此操作(如果它是 sessionTransacted)。