JMSConsumer骆驼处理器中的Spring @Transactional JPA

时间:2018-11-02 12:54:30

标签: java spring-boot apache-camel spring-transactions openjpa

我正在更新现有的Java SE Camel应用程序,以通过@PersitentContext注入来利用Spring JPA管理的EntityManger。当前,在我们的代码中使用Persistence.createEntityManagerFactory实例化了它,并且效果很好。但是,我们希望通过注入该entityManager来拥有更灵活和可测试的应用程序,使用强大的@Transactional aop功能,还可以通过使用不同的@Configuration @Profiles在本地和全局XA事务之间进行切换。

我的第一个测试是使用Atomikos TransactionManager测试涉及JMS和JPA资源的xa事务,并且可以正常工作。

现在在此应用程序中,我想使用OpenJPA,Camel和JpaTransactionManager测试本地事务,即不涉及XA事务。

我的单元测试在没有Camel的情况下效果很好,@ Transactional编织完成了使用jpaTransactionManager启动事务的工作,一切都很好。

现在,当我尝试将配置Bean集成到骆驼应用程序中时,一切进展不顺利。

我有一个JMS使用者,该使用者触发一个骆驼处理器,其中的处理方法用@Transactional注释。

我认为我配置有误,因为JMSConsumer很难启动事务,因为我没有明确设置JMS组件为事务性的(路由中没有transacted(),没有将事务管理器设置为JMSConfiguration)

这是一个断点,显示了JmsConsumer尝试注册到事务同步内容:

Daemon Thread [Camel (worker) thread #1 - JmsConsumer[<consumerName>]] (Suspended (breakpoint at line 175 in TransactionSynchronizationManager))
    TransactionSynchronizationManager.bindResource(Object, Object) line: 175
    DefaultJmsMessageListenerContainer(AbstractPollingMessageListenerContainer).doReceiveAndExecute(Object, Session, MessageConsumer, TransactionStatus) line: 313
    DefaultJmsMessageListenerContainer(AbstractPollingMessageListenerContainer).receiveAndExecute(Object, Session, MessageConsumer) line: 255
    DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener() line: 1168
    DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop() line: 1160
    DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run() line: 1057
    ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1142
    ThreadPoolExecutor$Worker.run() line: 617   
    Thread.run() line: 745 [local variables unavailable]

我看不到任何其他资源绑定到TransactionSynchronisationManager。

相反,在我的单元测试中似乎进展顺利,我们在堆栈中看到@Transactional发挥了预期的作用:

Thread [main] (Suspended (breakpoint at line 175 in TransactionSynchronizationManager))
    TransactionSynchronizationManager.bindResource(Object, Object) line: 175
    JpaTransactionManager.doBegin(Object, TransactionDefinition) line: 406
    JpaTransactionManager(AbstractPlatformTransactionManager).getTransaction(TransactionDefinition) line: 377
    TransactionInterceptor(TransactionAspectSupport).createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String) line: 461
    TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 277
    TransactionInterceptor.invoke(MethodInvocation) line: 96    
    CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 179
    CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 671
    MyRepo$$EnhancerBySpringCGLIB$$5edadd7f.createRun(String) line: not available
    DataSourceConfigTest.testIt2() line: 38 
    ...

所以显然这里有些配置错误,似乎@Transactional被SpringBoot的一些神奇的自动配置完全忽略或覆盖了。有人有任何提示吗?

这是我的CamelConfiguration和My Data / JPA配置

骆驼配置

@Configuration
public class CamelConfiguration {
    protected static Logger LOGGER = LoggerFactory.getLogger(CamelConfiguration.class);


    @Value("${broker.mqURL}")
    String mqURL;

    /**
     * The runId is injected from command Line arguments
     */
    @Value("${runId}")
    long runId;


    @Bean
    CamelContextConfiguration contextConfiguration() {
        return new CamelContextConfiguration() {
            @Override
            public void beforeApplicationStart(CamelContext context) {

                ((SpringCamelContext)context).setName("worker");

                DefaultShutdownStrategy shutdownStrategy = new DefaultShutdownStrategy();
                shutdownStrategy.setTimeUnit(TimeUnit.SECONDS);
                shutdownStrategy.setTimeout(5);
                context.setShutdownStrategy(shutdownStrategy);
            }

            @Override
            public void afterApplicationStart(CamelContext camelContext) {
                try {
                    LOGGER.info("Starting route dataspecProcessing." + runId);
                    camelContext.startAllRoutes();
                } catch (Exception e) {
                    LOGGER.error("Error during Camel post start",e);
                }
            }
        };
    }

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public ActiveMQConnectionFactory jmsConnectionFactory() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL(mqURL);
        connectionFactory.setTrustAllPackages(true);
        return connectionFactory;
    }

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public JmsConfiguration myJmsConfiguration(ActiveMQConnectionFactory jmsConnectionFactory,JpaTransactionManager jpaTransactionManager) {
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
//      jmsConfiguration.setTransacted(true);
//      jmsConfiguration.setLazyCreateTransactionManager(false);
//      jmsConfiguration.setTransactionManager(jpaTransactionManager);
        jmsConfiguration.setConnectionFactory(jmsConnectionFactory);
        jmsConfiguration.setCacheLevelName("CACHE_CONSUMER");
        return jmsConfiguration;
    }

Jpa配置

@Configuration
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DataSourceConfig {

    @Bean
    public JpaTransactionManager jpaTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        transactionManager.setDataSource(dataSource());
        transactionManager.setJpaDialect(new OpenJpaDialect());
        return transactionManager;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceXmlLocation("META-INF/persistence.xml");
        em.setJpaProperties(additionalProperties());
        em.setDataSource(dataSource());
        em.setValidationMode(ValidationMode.NONE);
        JpaVendorAdapter vendorAdapter = new OpenJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }

    @Bean
    public DataSource dataSource() {
        PGSimpleDataSource pgDataSource = new PGSimpleDataSource();
        pgDataSource.setUrl(...);
        pgDataSource.setUser(...);
        pgDataSource.setPassword(...);
        return pgDataSource;
    }

应该是可交易的代码

@Component
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MyCamelProcessor implements Processor {
...
@Transactional(propagation=Propagation.REQUIRES_NEW,transactionManager="jpaTransactionManager")
    public void process(Exchange exchange) throws Exception {
        ... calls to entitymanager here ...

调用处理器的路由

@Component
public class DataSpecProcessingRoute extends SpringRouteBuilder {
....
public void configure() throws Exception {
...
from("jms:queue:thequeue"?concurrentConsumers=" + numConsumerThreads)
            .autoStartup(false)
        .shutdownRunningTask(ShutdownRunningTask.CompleteCurrentTaskOnly)
                .routeId("dataspecProcessing." + runId)
                .process(initialisationProcessor)
                .process(processorWithTransactionnalNeeded)
.to("jms:queue:anotherqueue") ;

编辑

它适用于程序化事务,不适用于@Transactional注释。

0 个答案:

没有答案