Hibernate4.0之HibernateSessionFactory源码详解

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

@SuppressWarnings("deprecation")
public class HibernateSessionFactory {

    /**
     * Location of hibernate.cfg.xml file.
     * Location should be on the classpath as Hibernate uses
     * #resourceAsStream style lookup for its configuration file.
     * The default classpath location of the hibernate config file is
     * in the default package. Use #setConfigFile() to update
     * the location of the configuration file for the current session.
     */

    private static String CONFIG_FIEL_LOACTION = "/hibernate.cfg.xml";
    private static String configFile = CONFIG_FIEL_LOACTION;
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private static org.hibernate.SessionFactory sessionFactory;
    private static Configuration configuration = new Configuration();
    private static ServiceRegistry serviceRegistry; 

/**
   在回话工厂类HibernateSessionFactory中, 首先通过一次静态代码块来启动Hibernate,该代码块只在HibernateSessionFactory类被加载时执行一次,用于建立sessionFactory。即SessionFactory是线程安全的,只能被实例化一次。
在静态代码块中通过创建Configuration对象并调用其configure()方法读取Hibernate配置文件hibernate.cfg.xml信息,从而进行配置信息的管理。然后
创建SessionFactory实例,在Hibernate4.0版本之前,该实例创建工作由Configuration对象的buildSessionFactory()方法来完成。而Hibernater4.0版本之后,创建SessionFactory实例的方法有所改变,Hibernate 增加了一个注册ServiceRegistryBuilder类。要生成一个注册机对象,然后所有的生成
SessionFactory的对象向注册机注册一下再使用。生成方法还config.buildSessionFactory()方法,只不过加了一个注册机的参数。
*/
    static {
        try {
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Exception e) {
            System.err.println("%%%% Error Creating SessionFactory %%%%" + e);
            e.printStackTrace();
        }
    }

    private HibernateSessionFactory() {
    }

    /**
     * Returns the ThreadLocal Session instance.  Lazy initialize
     * the <code>SessionFactory</code> if needed.
     *
     * 由于sessionFactory是线程安全的,因而同一个SessionFactory实例可以被多个线程共享,即多个并发线程可以同时访问一个SesisonFactory并
     * 获得Session的实例。但由于Session不是线程安全的,如果多个并发线程同时操作同一个Session对象,就可能出现一个线程在进行数据库操作,而另一个
     * 线程将Session对象关闭的情况,从而出现异常。如何才能保证线程安全呢?这就要求SessionFactory能够针对不同的线程创建不同的Session对象,即
     * 需要对Session进行有效的管理,Hibernate中使用ThreadLocal对象来维护和管理Session实例。
     *
     * ThreadLocal是线程局部变量,线程局部变量高效的为每一个使用它的线程提供单独的线程局部变量的副本。为了实现为每个线程维护一个变量的副本,ThreadLocal
     * 类提供了一个Map结构,是key值用来保存线程的ID, value用来保存一个Session实例的副本。这样多线程并发操作时,实在与自己绑定的Session实例副本上进行
     * 的,从而避免多个线程横在同一个Session实例上操作是可能导致的数据异常。
     *
     * 在HibernaterSessionFctory类的getSession()方法中,首先调用ThreadLocal类的get()方法获得当前线程的Session对象,然后判断当前线程是否已存在
     * Session对象或者对象未打开,在判断SessionFactory对象是否为空,如果SeesionFctory对象不存在,先调用rebuildSessionFactory()方法创建SesionFactory,
     * 如果SessionFactory对象已经存在,则调用SessionFactory对象的openSession()方法创建Session对象。创建完Session对象后,还需要调用ThreadLocal的set()
     * 方法为该线程保存Session对象。
     *
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() {
        Session session = (Session) threadLocal.get();
        try{
            if (session == null || !session.isOpen()) {
                if (sessionFactory == null) {
                    rebuildSessionFactory();
                }
                session = (sessionFactory != null) ? sessionFactory.openSession()
                        : null;
                threadLocal.set(session);
            }
        } catch (HibernateException e){
            System.err.println("%%%% Error Creating getSession %%%%" + e);
            e.printStackTrace();
        }
        return session;
    }

    /**
     *  Rebuild hibernate session factory
     *
     */
    public static void rebuildSessionFactory() {
        synchronized(sessionFactory){
            try {
                configuration.configure(configFile);
                serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
                sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            } catch (Exception e) {
                System.err.println("%%%% Error rebuildSessionFactory %%%%" + e);
                e.printStackTrace();
            }
        }
    }

    /**
     *  Close the single hibernate session instance.
     *
     *  @throws HibernateException
     */
    public static void closeSession(){
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);
        try{
            if (session != null && session.isOpen()) {
                session.close();
            }
        } catch(HibernateException e){
            System.err.println("%%%% Error closeSession %%%%" + e);
            e.printStackTrace();
        }
    }

    /**
     *  return session factory
     *
     */
    public static org.hibernate.SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    /**
     *  return hibernate configuration
     *
     */
    public static Configuration getConfiguration() {
        return configuration;
    }

    public static void setConfigFile(String configFile){
        HibernateSessionFactory.configFile = configFile;
    }

}
时间: 2024-07-28 13:41:36

Hibernate4.0之HibernateSessionFactory源码详解的相关文章

走近VB.Net(三) 源码详解—运用颜色的初步探讨

详解 走近VB.Net(三) 源码详解-运用颜色的初步探讨 新建一个工程,加入以下控件1. label控件:label1,label2,labred ,labblue,labgreen2. picturebox控件:picturebox13. button控件:Button1设置form1的opacity属性为80%,设置透明的窗体在office中抓取一幅取色图片存为bmp格式,并设为picturebox1的backgroundimage,即背景图片Option Strict Off '关闭 s

Thrift的TProtocol类体系原理及源码详解:紧凑协议类TCompactProtocolT(TCom

Thrift的TProtocol类体系原理及源码详解:紧凑协议类TCompactProtocolT(TCompactProtocol) 这个协议类采用了zigzag 编码,这种编码是基于Variable-length quantity编码提出来 的,因为Variable-length quantity编码对于负数的编码都需要很长的字节数,而zigzag 编 码对于绝对值小的数字,无论正负都可以采用较少的字节来表示,充分利用了 Varint技术. 所以这个协议类采用zigzag 编码可以节省传输空

Thrift的TProtocol类体系原理及源码详解:二进制协议类TBinaryProtocolT(TBi

Thrift的TProtocol类体系原理及源码详解:二进制协议类TBinaryProtocolT(TBinaryProtocol) 这个协议是Thrift支持的默认二进制协议,它以二进制的格式写所有的数据,基本上直接 发送原始数据.因为它直接从TVirtualProtocol类继承,而且是一个模板类.它的模板参数 就是一个封装具体传输发送的类,这个类才是真正实现数据传输的.这个类的定义上一节举 例已经出现过了就不在列出来了. 下面我就结合scribe的Log函数执行的具体过程来 分析使用这个协

Android Matrix源码详解_Android

Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类.Android中的Matrix是一个3 x 3的矩阵,其内容如下:  Matrix的对图像的处理可分为四类基本变换: Translate           平移变换 Rotate                旋转变换 Scale                  缩放变换 Skew                  错切变换 从字面上理解,矩阵中的MSCALE用于处理缩放变换,MS

Android实现屏幕锁定源码详解_Android

最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下:   二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友

Android DownloadProvider 源码详解_Android

Android DownloadProvider 源码分析: Download的源码编译分为两个部分,一个是DownloadProvider.apk, 一个是DownloadProviderUi.apk. 这两个apk的源码分别位于 packages/providers/DownloadProvider/ui/src packages/providers/DownloadProvider/src 其中,DownloadProvider的部分是下载逻辑的实现,而DownloadProviderUi

Android实现屏幕锁定源码详解

最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

微信 小程序前端源码详解及实例分析_其它综合

微信小程序前端源码逻辑和工作流 看完微信小程序的前端代码真的让我热血沸腾啊,代码逻辑和设计一目了然,没有多余的东西,真的是大道至简. 废话不多说,直接分析前端代码.个人观点,难免有疏漏,仅供参考. 文件基本结构: 先看入口app.js,app(obj)注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等.其他文件可以通过全局方法getApp()获取app实例,进而直接调用它的属性或方法,例如(getApp().globalData) //app.js App({ onLau

ASP调用MSSQL存储过程并返回记录集源码详解

存储过程|记录集|详解 以下是asp代码(demo.asp):<%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%> <!--#include file="adovbs.inc"--> <% '通用的ASP读取MSSQL存储过程代码示例 '返回临时表记录集 '带传递参数 dim conn,connstr,cmd,rs connstr = "Provider=SQLOLEDB;serv