如何用Spring框架模块化Hibernate SessionFactory(下)

日期: 2011-11-21 作者:Ding Yun博士Karsten Klein翻译:杨华军 来源:TechTarget中国 英文

在《如何用Spring框架模块化Hibernate SessionFactory(上)》中,我们介绍了应用模块化方法概要、模块化及事务管理、利用Spring和Hibernate进行模块化等内容。下面我们将继续后半部分的内容。   SessionFactory交换   SessionFactory是在模块的范围内进行“交换”的。图2用一个包含有模块A、B、C的事务演示了SessionFactory交换的概念。

模块B随后调用了一个由模块C提供的服务。每一模块都有一个模块特有的SessionFactory,比如说,模块A的SessionFactory SFA ,而SFB则是对应于模块B的。 图2通过……

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

《如何用Spring框架模块化Hibernate SessionFactory(上)》中,我们介绍了应用模块化方法概要、模块化及事务管理、利用Spring和Hibernate进行模块化等内容。下面我们将继续后半部分的内容。

  SessionFactory交换

  SessionFactory是在模块的范围内进行“交换”的。图2用一个包含有模块A、B、C的事务演示了SessionFactory交换的概念。模块B随后调用了一个由模块C提供的服务。每一模块都有一个模块特有的SessionFactory,比如说,模块A的SessionFactory SFA ,而SFB则是对应于模块B的。

图2通过共享数据库连接进行的跨会话工厂的事务同步

图2通过共享数据库连接进行的跨会话工厂的事务同步

  在进入模块之前,当前跟事务管理器绑定在一起的SessionFactory被放到一边,要进入的模块的SessionFactory则被绑定到事务管理器(见图2,红色箭头正在进入模块中)。在离开模块时,事务管理器则恢复到之前的SessionFactory(参见绿色箭头,正在离开模块返回的途中)

  这引发了一个问题,怎么才能知道模块边界被穿越了呢?按照OSGi和Spring DM的面向服务机制,每个模块都声明了一组其引入和导出的服务(如Spring beans)。调用一个导出的服务会被一个代理对象拦截。也就是说,代理是知道边界被跨越的,在调用实际提供服务的bean之前和之后实现SessionFactory交换的代码即可。

  事务同步

  既然一个逻辑跨模块的事务被映射到了多个Spring事务上,我们就必须跟踪属于一个逻辑事务的那些Spring事务,以便对其进行协调。如图3所示,我们使用了一个跟线程绑定的传播栈(propagation stack)来跟踪进行中的Spring事务,以及根据事务传播行为确定的父子关系。在图3中,方括号代表了事务的边界。txA表示事务A的,并与SessionFactory SFA相关联。

图3 跟踪从属于一个逻辑事务的Spring事务的传播栈

图3 跟踪从属于一个逻辑事务的Spring事务的传播栈

  通过对从属同一个逻辑事务的事务的跟踪,我们就能够识别参与到逻辑事务的事务资源以便对其进行同步。如果事务资源共享同一数据源,他们就通过相同的数据库连接进行同步(见图1)。

  逻辑事务注解

  值得一提的是,具有requires-new传播行为的被已有事务调用的事务并非父逻辑事务的一部分。requires-new事务打开其自身新的事务资源(如数据库连接),这跟外部的逻辑事务的事务资源是不同步的。

  说得更具体一点,一切子事务(见图2,事务txB和 txC分别与SessionFactory SFB 和 SFC对应)都重用了其自身父事务的数据库连接(此例中为事务txA)。通常而言,Spring会为txB打开一个新的会话。除了使用同一个数据库连接之外,所有子事务的完成都要延迟到父事务的结束。作为提交(commit)操作的一部分,flush操作必须对所有涉及的会话加以执行。

  缺省情况下,我们假定应用的模块共享同一个数据源。确实存在领域特有的场景,需要模块使用独立的、专门的数据源。比如说,加密或安全审计的模块也许需要在一个独立的数据库来存储敏感的加密参数或审计数据。我们已经在一个专有框架内实现了自己的Spring扩展,并引入了客户化的事务名字空间来将避免应用编码的复杂性。使用这一客户化的事务名字空间,模块显式地声明了自己并没有使用该应用的共享数据库。

  模块化SessionFactory的优点

  通过SessionFactory交换以及共享事务资源模式来扩展Spring事务管理是一项非常具有挑战性的任务。我们的扩展包含了对声明式事务和编程式事务管理的此二者的支持,还支持事务测试。在对全局SessionFactory进行模块化之后,我们测出事务的吞吐量更高了(3-5%),尽管SessionFactory交换及事务同步会引起过载。

  通过这些模块特定的会话工厂,模块的边界变得要清晰得多了。Listener跟interceptor都可以注册到一个感兴趣的特定模块的SessionFactory上。他们从模块特定的SessionFactory上接收的调用要远远少于从全局SessionFactory上所接收的调用。这一差异解释了在引入模块特定的会话工厂之后事务吞吐量的增加。

  此外,模块的内部会话工厂现在可单独配置来迎合其模块的需要。比方说,这使得专门缓存或特定复制配置等其他选项的使用成为可能,这一切在过去都是不可能的。

  OSGi的模块化

  自打Peter Kriens有关在OSGi服务平台利用Hibernate进行类加载和全局SessionFactory配置的博客[1]发表以来,各种解决方案都提出来了。这些方案大都依靠Require-Bundle、Dynamic-Import或Eclipse-Buddy策略,但是它们都不能彻底解决问题。最近OSgi JPA服务规范[3]针对这些问题提出了一个新方案。

  根据这份规范,一个持久层绑定包含有实体类和随之而来的持久层描述(类似于Hibernate SessionFactory的配置)。对于持久层描述器的每一个持久层单元来说,JPA提供者都注册了一个Entity Manager Factory (Builder)服务,该服务可通过一个与绑定的操纵实体类的客户获得。OSGi JPA方案跟我们的采用Spring 和Hibernate的方案是类似的。

  一旦来自于不同包的多个实体管理器加入进来,多个数据库会话或连接就会为跨包的事务打开。为了保证事务的原子性,最重要的是要了解哪个事务资源属于逻辑事务。OSGi JTA事务服务规范[3]引入了征募策略(enlistment strategy)。事务资源会把自己征募/关联到一个进行中的事务去,以便参与到资源提交的协调当中来。

  我们的方案利用了诸如事务传播行为之类的信息以及底层数据源来对从属于一耳光逻辑事务的事务资源进行跟踪。对于XA资源如何进行协调,以及在存在共享数据源的情况下,这些协调可以如何进行优化,OSGi规范都没有细述。这个任务仍旧留给了具体的JTA提供者或底层资源管理器身上(如数据库)。对于我们的方案和OSGi策略的深入比较已经超出本文范围了。

  关于作者

  Ding Yun博士和Karsten Klein是InterComponentWare (ICW) AG的软件架构师。ICW公司是位于德国沃尔多夫的一家专门提供医疗保健行业的技术解决方案的国际公司。所有ICW的解决方案均基于ICW的eHealth平台建立的,这个平台为支持eHealth解决方案的快速部署以及集成场景的灵活实现提供了强大的技术组件。两位作者均经常为企业应用会议及研究出版物撰稿。

相关推荐