TransactionSynchronizationFactory与JmsTransactionManager结合使用不起作用

时间:2017-02-07 07:25:22

标签: spring-integration

我有一个案例,我在那里读取文件,将内容转换为String。然后将字符串拆分为多个有效负载,并将这些有效负载单独发送到队列。我想使用JmsTransactionManager以便所有消息都发送或根本不发送。

当TX成功时,我想将文件移动到Archive文件夹,否则将其移动到Failed文件夹。我已经读过,我可以使用transactionSynchronizationFactory来完成此任务。但是与JmsTransactionManager结合使用时,文件不会移动。如果我使用PseudoTransactionManager,那么文件就会被移动,但是我的JmsTransaction就失去了。

我制作了一个简化版本来重现这个问题。 (在这种情况下,文件的内容是一个简单的逗号分隔值列表。)

@Bean
public IntegrationFlow fileInboundAdaptor() {
    return IntegrationFlows
            .from(s -> s.file(new File(INBOUND_PATH))
                            .patternFilter("*.txt"),
                    e -> e.poller(Pollers.fixedDelay(5000)
                            .transactionSynchronizationFactory(transactionSynchronizationFactory())
                            .transactional(new JmsTransactionManager(connectionFactory))

                    )

            )

            .transform(Transformers.fileToString())
            .split(s -> s.applySequence(false).get().getT2().setDelimiters(","))
            .handle((GenericHandler<String>) (payload, headers) -> {
                jmsTemplate.send("SOME_QUEUE", (Session session) -> session.createTextMessage(payload));
                return payload;
            })
            .channel(MessageChannels.queue("fileReadingResultChannel"))
            .get();
}

transactionSynchronizationFactory如下所示:

@Bean
public TransactionSynchronizationFactory transactionSynchronizationFactory() {
    ExpressionParser parser = new SpelExpressionParser();

    ExpressionEvaluatingTransactionSynchronizationProcessor syncProcessor
            = new ExpressionEvaluatingTransactionSynchronizationProcessor();
    syncProcessor.setBeanFactory(applicationContext.getAutowireCapableBeanFactory());
    syncProcessor.setAfterCommitExpression(parser.parseExpression(
            "payload.renameTo(new java.io.File('test/archive' " +
                    " + T(java.io.File).separator + 'ARCHIVE-' + payload.name))"));
    syncProcessor.setAfterRollbackExpression(parser.parseExpression(
            "payload.renameTo(new java.io.File('test/fail' " +
                    " + T(java.io.File).separator + 'FAILED-' + payload.name))"));
    return new DefaultTransactionSynchronizationFactory(syncProcessor);
}

所以我的问题是:TransactionSynchronizationFactory只能与PseudoTransactionManager一起使用,还是应该与JmsTransactionManager一起使用?

解决方案

我需要在JmsTransaction上设置transactionSynchronization。像这样:

public JmsTransactionManager transactionManager() {
    JmsTransactionManager jmsTransactionManager = new JmsTransactionManager(connectionFactory);
    jmsTransactionManager.setTransactionSynchronization(AbstractPlatformTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
    return jmsTransactionManager;
}

1 个答案:

答案 0 :(得分:0)

嗯,我认为你的问题在这里:

/**
 * Create a new JmsTransactionManager for bean-style usage.
 * <p>Note: The ConnectionFactory has to be set before using the instance.
 * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
 * typically setting the ConnectionFactory via setConnectionFactory.
 * <p>Turns off transaction synchronization by default, as this manager might
 * be used alongside a datastore-based Spring transaction manager like
 * DataSourceTransactionManager, which has stronger needs for synchronization.
 * Only one manager is allowed to drive synchronization at any point of time.
 * @see #setConnectionFactory
 * @see #setTransactionSynchronization
 */
public JmsTransactionManager() {
    setTransactionSynchronization(SYNCHRONIZATION_NEVER);
}

因此,您必须手动将其切换为setTransactionSynchronization(AbstractPlatformTransactionManager.SYNCHRONIZATION_ALWAYS);