解读《使用Jencks实现Hibernate与Jackrabbit的分布式事务》
前言
?
本文是针对《使用Jencks实现Hibernate与Jackrabbit的分布式事务》(以下简称《JHJ》)一文的理论分析。若只关心实现,请忽略此文点击这里跳转到实现的参考示例。
?
本文先简单介绍JTA和JCA的一些概念作为理论基础,之后再分析Jencks如何实现Hibernate与Jackrabbit的分布式事务的。
有关JTAJTA全称为Java Transaction API,顾名思义JTA定义了一组统一的事务编程的接口,这些接口如下:
?
XAResource
?
XAResource接口是对实现了X/Open CAE规范的资源管理器 (Resource Manager,数据库就是典型的资源管理器) 的抽象,它由资源适配器 (Resource Apdater) 提供实现。XAResource是支持事务控制的核心。
TransactionTransaction接口是一个事务实例的抽象,通过它可以控制事务内多个资源的提交或者回滚。二阶段提交过程也是由Transaction接口的实现者来完成的。
?
TransactionManager?
托管模式?(managed mode)?下,TransactionManager接口是被应用服务器调用,以控制事务的边界的。
?
UserTransaction非托管模式?(non-managed mode)?下,应用程序可以通过UserTransaction接口控制事务的边界
?
托管模式下的事务提交场景
?
?
?
Enterprise Information System简称EIS,在JTA中它又被称为资源管理器。典型的EIS有数据库,事务处理系统(Transaction Processing System),ERP系统。
?
Resource Adapter资源适配器(Resource Adaper)是JCA的关键。要想把不同的EIS整合(或者连接)到J2EE运行环境中,就必须为每个EIS提供资源适配器,它会将将EIS适配为一个具备统一编程接口的资源 (Resource) 。这个统一编程接口就是上图中的System Contracts和Client API。下面的UML类图将完美诠释资源适配器。
?

?
应用服务器 (Application Server) 通过System Contracts来管理对EIS的安全、事务、连接等。典型的应用服务器有JBoss、JOnAS、Geronimo、GlassFish等。
?
Application Component?应用组件 (Application Component) ,它封装了应用业务逻辑,像对资源的访问和修改。典型的应用组件就是EJB。
?
更多细节请参见:
?
实现分析回到用《JHJ》的问题上来,上面关于JTA与JCA到底能够提供哪些帮助呢?总结一下有两点:
?
众所周知,应用服务器是提供事务管理器实现的,但这不意味着我们只能选择应用服务器,不然就没有必要写《JHJ》和此文了。这里我选择了Jencks,它是一个轻量级的JCA容器,能够很容易与Spring进行集成,并由Spring的JtaTransactionManager将事务管理的职责委派给Jencks。
?
?
<!-- Jackrabbit --><bean id="repository"/></property><property name="connectionManager"><bean parent="connectionManager" /></property></bean><!-- Database --><bean id="dataSource" ref="jdbcManagedConnectionFactory" /><property name="connectionManager"><bean parent="connectionManager" /></property></bean>?ConnectionManagerFactoryBean将ConnectionManager与TransactionManager关联上;<!-- 链接管理器 --><bean id="connectionManager" abstract="true"><property name="transactionManager"><ref local="delegateTransactionManager" /></property><property name="transaction" value="xa" /></bean>?ManagerConnectionFactory创建的连接工厂都注入了ConnectionManager,为是让ConnectionManager来管理连接的分配,并enlistReource。
// DataSourceMCF.javapublic Object createConnectionFactory(ConnectionManager connectionManager) throws ResourceException {return new DataSource(this, connectionManager);}// JCAManagedConnectionFactory.javapublic Object createConnectionFactory(ConnectionManager cm)throws ResourceException {createRepository();JCARepositoryHandle handle = new JCARepositoryHandle(this, cm);log("Created repository handle (" + handle + ")");return handle;}?
?
// DataSource.javapublic Connection getConnection() throws SQLException {try {return (Connection) cm.allocateConnection(mcf, containerRequestInfo);} catch (ResourceException e) {...}}// JCARepositoryHandle.javaprivate Session login(JCAConnectionRequestInfo cri)throws LoginException, NoSuchWorkspaceException, RepositoryException {try {return (Session) cm.allocateConnection(mcf, cri);} catch (ResourceException e) {...}}?
?
?
// GenericConnectionManager.javapublic Object allocateConnection(ManagedConnectionFactory managedConnectionFactory, ConnectionRequestInfo connectionRequestInfo)throws ResourceException {ManagedConnectionInfo mci = new ManagedConnectionInfo(managedConnectionFactory, connectionRequestInfo);ConnectionInfo ci = new ConnectionInfo(mci);getStack().getConnection(ci); // 这里通过拦截器机制完成事件监听注册和enlistReourceObject connection = ci.getConnectionProxy();if (connection == null) {connection = ci.getConnectionHandle();}return connection;}// MCFConnectionInterceptor.javapublic void getConnection(ConnectionInfo connectionInfo) throws ResourceException {// ManagedConnectionInfo mci = ...try {// ManagedConnection mc = ......GeronimoConnectionEventListener listener = new GeronimoConnectionEventListener(stack, mci);mci.setConnectionEventListener(listener);mc.addConnectionEventListener(listener);} catch (ResourceException re) {...}}// TransactionEnlistingInterceptor.javapublic void getConnection(ConnectionInfo connectionInfo) throws ResourceException {next.getConnection(connectionInfo);try {ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();Transaction transaction = TxUtil.getTransactionIfActive(transactionManager);if (transaction != null) {XAResource xares = mci.getXAResource();transaction.enlistResource(xares);}} catch (Exception e) {...}}?
?
小结解读《JHJ》的目的只为抛砖引玉,激发思考和探讨。此外,这里留下一个问题,在Spring的JtaTransactionManager的源码中发现,spring使用的是UserTransaction而不是TransactionManager这是为何呢?
?
?
?
?
1 楼 whaosoft 2009-01-17 呵呵 学习一下哈