Hibernate实战_笔记15(JavaEE服务JTA、JNDI、JMX整合)

与Java EE服务整合

      假设你已经试过了前面介绍过的示例,并且熟悉基础的Hibernate配置,以及Hibernate如何与简单的Java应用程序整合。现在,我们要讨论更高级的原生的Hibernate配置选项,以及一般的Hibernate应用程序如何使用Java EE应用程序服务器提供的Java EE服务。
      Java EE应用程序服务器,例如JBoss AS、BEA WebLogic和IBM WebSphere,为Java实现标准的(特定于Java EE)的托管环境。Hibernate能够与之整合的三大最值得关注的Java EE服务是JTA、JNDI和JMX。
      JTA允许Hibernate参与托管资源中的事务。Hibernate可以通过JNDI查找托管资源(数据库连接),并且能够把自身当作一项服务绑定到JNDI上。最后,Hibernate可以通过JMX被部署,然后通过JMX容器被当作一项服务来管理,并且使用标准的JMX客户端程序在运行时被监控。
来看看每一项服务,以及如何把Hibernate与它整合起来。

与JTA整合

      JTA是Java企业应用中事务控制的标准服务接口。它公开了几个接口,例如用于事务划分的UserTransaction API和用于参与列事务生命周期中的TransactionManager API。事务管理器能够协调跨资源的单个事务。
      JTA事务服务由所有Java EE应用程序服务器提供。然而,许多Java EE服务可以被独立使用,并且可以给应用部署JTA提供程序,例如JBoss Transaction或者Object Web JOTM。我们对于配置的这部分不多说,而是关注Hibernate与JTA服务的整合,在完全的应用程序服务器中或者使用独立的JTA提供程序时也一样。

      看看图2-6。使用Hibernate的Session接口访问(多个)数据库,Hibernate的责任是与托管环境的Java EE服务整合。


      在这样一个托管环境中,Hibernate不再创建和维护JDBC连接池——Hibernate通过在JNDI注册中查找Datasource对象获得数据库连接。因此,你的Hibernate配置需要一个对JNDI名称的引用,在这个引用中能够获得托管的连接。
<hibernate-configuration>
	<session-factory>
		<property name="hibernate.connection.datasource">java:/MyDataSource</property>
		<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
		...
	</session-factory>
</hibernate-configuration>
      利用这个配置文件,Hibernate使用名称java:/MyDatasource在JNDI中查找数据库连接。当你配置应用程序服务器和部署应用程序时,或者当你配置独立的JTA提供程序时,这就是你应该把托管的数据源绑定到上面的名称。注意Hibernate仍然需要一个方言设置来生成正确的SQL。
      说明:Hibernate和Tomcat——Tomcat不是一个Java EE应用程序服务器;它只是一个servlet容器,虽然servlet容器具有一些通常只有应用程序服务器才有的特性。这些特性中有一种可以与Hibernate共用:Tomcat连接池。Tomcat内部使用DBCP连接池,但是把它当作一个JNDI数据源公开,就像真实的应用程序服务器一样。记住,Tomcat不提供事务管理器,你仍然有个简单的JDBC事务语义,Hibernate可以用可选的Transaction API把它隐藏起来。另一种方法是,可以与你的Web应用程序一起部署一个可与JTA兼容的、独立的事务管理器,考虑用它获得标准的UserTransaction API。另一方面,一般的应用程序服务器(尤其当它像JBoss As一样模块化时)可能比在Tomcat加DBCP加JTA更易配置,并且提供更好的服务。
要完全把JTA与Hibernate整合,需要告诉Hibernate更多有关事务管理器的信息。
<hibernate-configuration>
	<session-factory>
		<property name="hibernate.connection.datasource">java:/MyDataSource</property>
		<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
		<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
		<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
		...
	</session-factory>
</hibernate-configuration>
      你要给应用程序服务器选择适当的查找类,就如在前面的代码中所做的那样——Hibernate给最普及的JTA提供程序和应用程序服务器绑定了类。最后,告诉Hibernate要在应用程序中使用JTA事务接口设置事务范围。JTATransactionFactory完成几件事:
1)它为JTA启用了正确的Session范围和传播
2)它告诉Hibernate你正准备在应用程序中调用JTAUserTransaction接口;来启动、提交或者回滚系统事务。
3)万一你不想使用标准的UserTransaction,它还把Hibernate Transaction API切换到JTA。如果你现在使用Hibernate API启动事务,它会检查是否有JTA事务正在进行中,如果有可能,参与这个事务。如果没有JTA事务正在进行,就会启动一个新事务。如果你在一个支持JTA的环境中部署的话,不建议使用Hibernate Transaction API。然而,这个设置使现有的代码可以在托管和非托管环境之间移植,虽然它可能使用不同的事务行为。
      还有其他内建的TransactionFactory选项,并且你可以通过实现这个接口编写。JDBCTransactionFactory在非托管环境中是默认的。如果使用JTA和EJB,并且计划在托管的EJB组件上声明设置事务范围——换句话说,如果要在一个Java EE应用程序服务器中部署EJB应用,但不在应用程序代码中使用UserTransaction接口编程式地设置事务范围——就应该启用CMTTransactionFactory。
按偏好顺序排列,我们建议的配置选项如下:
1)如果应用程序必须在托管和非托管环境中运行,应该把事务整合和资源管理的任务转给部署程序。在应用程序代码中调用JTA的UserTransaction API,让应用程序的部署程序相应地配置应用程序服务器或者独立的JTA提供程序。在Hibernate配置中启用JTATransaction,与JTA服务整合,并设置正确的查找类。
2)考虑使用EJB组件通过声明设置事务范围。数据访问代码并没有被绑定到任何事务API,CMTTransactionFactory在后台为你整合和处理Hibernate Session。这是最容易的解决方案——当然,现在部署程序有责任提供一个支持JTA和EJB组件和环境。
3)用Hibernate Transaction API编写代码,并通过设置JDBCTransactionFactory或者JTATransactionFactory,让Hibernate在不同的部署环境中切换。注意事务语义可能改变,并且事务的启动或者提交可能导致一个你无法预料的空操作(no-op)。当需要事务划分的可移植性时,这永远是最后一种选择。

JNDI绑定的SessionFactory

      SessionFactory应该如何存储,以及它在应用程序代码中应该如何访问?通过编写一个在静态字段中存放SessionFactory的HibernateUtil类,并提供静态的getSessionFactory()方法。然而,如果在一个支持JNDI的环境中部署应用程序,Hibernate可以把SessionFactory绑定到JNDI,你需要时可以到那里查找。
      如果hibernate.session_factory_name属性设置为JNDI节点的名称,Hibernate的SessionFactory就会自动把自身绑定到JNDI。如果运行时环境不提供默认的JNDI上下文(或者如果默认的JNDI实现不支持Referenceable的实例),就需要使用hibernate.jndi.url和hibernate.jndi.class属性指定一个JNDI的初始上下文。
这里有一个例子,说明利用Sun公司基于文件系统(file-system-based)的JNDI实现fscontext.jar,把SessionFactory绑定到java:/hibernate/MySessionFactory的Hibernate配置:
hibernate.connection.datasource=java:/MyDatasource
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect=org.hibernate.dialect.OracleDialect
hibernate.session_factory_name=java:/hibernate/MySessionFactory
hibernate.class=com.sun.jndi.fscontext.RefFSContextFactory
hibernate.url=file:/auction/jndi
      当然,也可以使用基于XML的配置文件。这个例子是不现实的,因为通过JNDI提供连接池的大部分应用程序服务器,还包含可编写的默认上下文的一个JNDI实现。JBoss AS必然也有,因此可以跳过最后两个属性,只要给SessionFactory指定一个名称即可。
      说明:JNDI和Tomcat——Tomcat提供一个只读的JNDI上下文,servlet容器启动后,它不可以从应用程序级代码中编写。Hibernate无法绑定到这个上下文:你必须使用一个完全的上下文实现(如Sun FS上下文),或者通过在配置中省略session_factory_name属性,禁用SessionFactory的JNDI绑定。
      为了保证应用程序代码的可移植,你可能想要实现这个构建以及HibernateUtil中的查找,并在你的数据访问代码中继续使用辅助类。
package cn.jbit.hibernate.util;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class HibernateUtil {


	private static Context jndiContext;


	static {
		try {
			new Configuration().buildSessionFactory();
			jndiContext = new InitialContext();
		} catch (Throwable ex) {
			throw new ExceptionInInitializerError(ex);
		}
	}
	
	private HibernateUtil() {
	}


	public static SessionFactory getSessionFactory(String jndiName) {
		SessionFactory sf;
		try {
			sf = (SessionFactory) jndiContext.lookup(jndiName);
		} catch (NamingException ex) {
			throw new RuntimeException(ex);
		}
		return sf;
	}
}
      另一种方法是,可以用一个JNDI调用直接在应用程序代码中查找SessionFactory。然而,在应用程序的某个地方,仍然至少需要启动代码的new Configuration().buildSessionFactory()行。去除Hibernate启动代码的这最后一行,并完全消除HibernateUtil类的一种方法是,把Hibernate部署为一项JMX服务(或者通过使用JPA和Java EE)。

JMX服务部署

      Java的世界充满了这些规范、标准和实现。一个相对较新但是很重要的标准是它的第一版:Java管理扩展(Java Management Extension,JMX)。JMX是关于系统组件管理或者系统服务管理的。
JMX规范定义了下列组件:
1)JMX MBean——可以重用的一个组件,给管理公开接口。
2)JMX容器(container)——调解对MBean的一般访问(本地的或者远程的)。
3)JMX客户端程序(client)——可能通过JMX容器用来管理任何MBean。
      支持JMX的应用程序服务器(例如JBoss AS)表现得就像JMX容器一样,并允许MBean被配置和初始化成应用程序服务器启动过程的一部分。你的Hibernate服务可能被打包和部署为JMX MBean;给这个绑定的接口是org.hibernate.jmx.HibernateService。可以用任何标准的JMX客户端程序通过这个接口启动、停止和监测Hibernate核心。另一个可以选择进行部署的MBean接口是org.hibernate.jmx.StatisticsService,它让你用一个JMX客户端程序启用监测Hibernate的运行时行为。
      JMX服务和MBean如何部署是特定于供应商的。例如,在JBoss应用程序服务器中,你只需要添加jboss-service.xml文件到应用的EAR,把Hibernate部署为一个托管的JMX服务。
这里不对每一个选项进行解释,JBoss应用程序服务器的信息请见参考文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值