Karaf教程第7部分- Camel JPA和JTA事务

来源:互联网 发布:log4j 只输出sql 编辑:程序博客网 时间:2024/05/22 02:04

Karaf教程第7部分- Camel JPA和JTA事务

Camel实践:轮询数据库表并发送XML内容到jms队列。路由使用JTA事务同步DBJMS事务。错误案例演示了如何处理异常。

路由和概览

jpa_route

from("jpa://net.lr.tutorial.karaf.camel.jpa2jms.model.Person").id("jpa2jms")

.onException(Exception.class).maximumRedeliveries(3).backOffMultiplier(2).handled(true).to("file:error")

.transacted()

.marshal(df)

.bean(new ExceptionDecider())

.to("jms:person");

路由起始于jpa的终结点。它用JPA @Entity的全限定名配置。从这个实体camel中,我们知道要轮询的表格,如何读,如何删除行。Jpa终结点轮询表格,从它找到的每一行记录转换为Person实例。然后调用路由中的下一步,Person对象作为bodyJpa组件也需要分开设置,因为它需要EntityManagerFactory

onException子句会让路由重试三次,每次用因子2增加补偿时间。如果仍然失败,那么消息就会被传递给error目录下的某个文件。

下一步中的transacted()标记路由为事务性的,它需要在camel上下文中设置 TransactedPolicy。然后它确保路由中的每一步都有机会参与到事务中。这样如果有错误发生,那么所有的动作都可以回滚。一旦都成功了,那么可以一起提交。

marshal(df)使用JAXBPerson对象转换为xml格式。它引用了数据格式对象df,它设置了JAXBContext。为了简化,这里设置不再说明。

ExceptionDecidet bean允许触发一个异常,如果Person的名字错误。这允许我们稍后测试错误处理。

最后一步("jms:person") 发送xml表示的personjmx队列。它要求命名为jmsJmsComponent组件设置到camel上下文中。

from("jms:person").id("jms2log")

.transacted()

.convertBodyTo(String.class)

.to("log:personreceived");

第二条路由简单地监听person的队列,读取和显示队列的内容。在生产系统中,这一部分通常是在另一个模块中。

Person作为JPA实体JAXB

Person类 是一个JPA实体,也是一个JAXB注解类。这允许我们在camel-jpa组件中使用它,也可以在marshall中使用它。记住,虽然可以这么干,但是这却是一个不良习惯,因为它将DB模型和JMS消息格式紧紧绑在一起。所以对于实际的集成,JPAJAXBBean要分开,手动实现它们之间的转换时最好的。

@Entity

@XmlType

@XmlRootElement

public class Person {

    private String name;

    private String twitterName;

 

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public String getTwitterName() { return twitterName; }

    public void setTwitterName(String twitterName) { this.twitterName = twitterName; }

}

DataSourceConnectionFactory设置

我们使用XADataSource作为Derby (参见 https://github.com/cschneider/Karaf-Tutorial/blob/master/db/datasource/datasource-derby.xml)数据由于KarafActiveMQ提供默认ConnectionDactory不是XA,我们手动定义代理和ConnectionFactory (参见https://github.com/cschneider/Karaf-Tutorial/blob/master/cameljpa/jpa2jms/localhost-broker.xml)Karaf事务特性一起,这些提供了JTA事务的基础。

JPAComponent, JMSComponent和事务设置

这个例子的最重要部分就是在JTA事务中使用jpajms组件。这将允许在错误发生时进行双回滚。下面是我们使用的一个blueprint上下文。我们使用OSGi服务ConnectionFactory设置JMS组件。EntityManagerFactory 使用来自Aries JPAjpa:unit配置设置JPAComponent。参见Apache Karaf教程第6部分–数据库访问,了解它的工作原理。Aries事务提供的TransactionManager被引用为OSGi服务,包装为spring PlattformTransactionManager,被注入到 JmsComponentJPAComponent

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"

    xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.1.0"

    xsi:schemaLocation="

  http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd

  http://www.osgi.org/xmlns/blueprint-ext/v1.1.0 https://svn.apache.org/repos/asf/aries/tags/blueprint-0.3.1/blueprint-core/src/main/resources/org/apache/aries/blueprint/ext/blueprint-ext.xsd

  http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd

  http://aries.apache.org/xmlns/jpa/v1.1.0 http://aries.apache.org/schemas/jpa/jpa_110.xsd

  ">

 

 <reference id="connectionFactory" interface="javax.jms.ConnectionFactory" />

<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">

  <property name="connectionFactory" ref="connectionFactory"/>

   <property name="transactionManager" ref="transactionManager"/>

 </bean>

 <bean id="jms" class="org.apache.camel.component.jms.JmsComponent">

  <argument ref="jmsConfig"/>

 </bean>

 <reference id="jtaTransactionManager" interface="javax.transaction.TransactionManager"/>

 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

  <argument ref="jtaTransactionManager"/>

  </bean>

 <bean id="jpa" class="org.apache.camel.component.jpa.JpaComponent">

  <jpa:unit unitname="person2" property="entityManagerFactory"/>

  <property name="transactionManager" ref="transactionManager"/>

 </bean>

 <bean id="jpa2jmsRoute" class="net.lr.tutorial.karaf.camel.jpa2jms.Jpa2JmsRoute"/>

 <bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy">

  <property name="transactionManager" ref="transactionManager"/>

 </bean>

 <camelContext id="jpa2jms" xmlns="http://camel.apache.org/schema/blueprint">

  <routeBuilder ref="jpa2jmsRoute" />

 </camelContext>

</blueprint>

运行示例

你可以在github上找到完整的例子:JPA2JMS Example。跟着Readme.txt文件,安装必要的karaf特性、bundle、配置。

除了本示例工程,我们也安装了dbexamplejpa。这将允许我们使用那里定义的person:add命令添加到数据库表。

打开Karaf控制台,键入如下命令:

person:add "Christian Schneider" @schneider_chris

log:display

你应该能看到如下的日志:

2012-07-19 10:27:31,133 | INFO  | Consumer[person] | personreceived ...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<person>

 <name>Christian Schneider</name>

 <twitterName>@schneider_chris2</twitterName>

</person>

发生了什么?

我们使用命令person:addperson表中增加了一行记录。 我们的路由获得这条记录,读取并将其转换为Person对象。然后将它转换为xml,并发送到jms 队列。我们的第二条路由然后获得jms消息,并在日志中显示出来。

错误处理

这个例子中的路由包含一个小bean,它对Person对象的名字进行响应,如果名字是”error”,那么就会抛出异常。它也包含一个错误处理,所以一旦发生异常,xml会被转发到错误目录。

所以你可以在karaf中键入如下命令:

person:add error error

log:display

这次日志不应该显示xml了。取而代之的是,它应该出现在karaf安装目录下的错误目录中的文件中。

总结

在这个教程中,主要的事情就是学习如何使用camel-jpa组件写入,就像轮询数据库一样,如何设置和使用jta事务获取固定的错误处理。

原创粉丝点击