hibernate源码分析——初始流程

如果要写一个Hibernate的Hello World程序,我们大概需要做这么几件事情:

1. 创建对应表的实体类并编写其到对应表的映射文件;

2. 编写hibernate的配置文件,默认是hibernate.cfg.xml,你当然可以用其它的名字,只需自己传递配置文件名称给Configure就好;

3. 编写具体操作数据库的dataservice;

对于第三步,又可分为:创建SessionFactory;获取session;通过session对象执行数据库操作;等等

如Hibernate中一个Tutorial:

public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

这个工具类中创建了sessionFactory对象,其它的数据服务类都可以使用。(我们应该知道SessionFactory是一个比较“重”的对象,创建的开销过大,一般一个数据库使用一个SessionFactory)

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ……

        try {
            // Begin unit of work
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().beginTransaction();  //通过SessionFactory获取session并开始事务

           ……
                    createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));  //数据库操作
           ……

        } catch (Exception ex) {
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().getTransaction().rollback();   //异常则回滚事务
            throw new ServletException(ex);
        }
    }

  protected void createAndStoreEvent(String title, Date theDate) {
        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);

        HibernateUtil.getSessionFactory()
                        .getCurrentSession().save(theEvent);   //通过session的save方法保存对象到数据库
    }

 

这里无关的代码我都给删除了,可以看到其流程跟前面提到的第三部基本是一致的。下面便来分析一下这段代码的背后,Hibernate做了什么?整个过程的时序图如下:

hibernate01

Configuration构造函数中会创建Mapping和SettingsFactory,它们会在后续用于解析SessionFactory的配置属性,之后调用Configuration的configure()函数,在configure()中将通过doConfigure函数完成对Hibernate配置文件hibernate.cfg.xml的解析。

解析完配置文件后,便可以通过BuildSessionFactory()创建SessionFactory了,在这个函数中,首先在buildSettings()中通过之前创建的SettingsFactory建立各种属性设置,之后通过new一个SessionFactoryImpl完成SessionFactory的创建。

有了SessionFactory,Client端便可以通过它获取Session,并执行各种数据库操作了。

从getCurrentSession()函数中可以知道,Session是从CurrentSessionContext获取的,那么CurrentSessionContext是怎么来的?可以来看看buildCurrentSessionContext函数的实现:

  private CurrentSessionContext buildCurrentSessionContext() {
    String impl = this.properties.getProperty("hibernate.current_session_context_class");

    if ((impl == null) && (this.transactionManager != null)) {
      impl = "jta";
    }

    if (impl == null) {
      return null;
    }
    if ("jta".equals(impl)) {
      if (this.settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions()) {
        log.warn("JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()");
      }
      return new JTASessionContext(this);
    }
    if ("thread".equals(impl)) {
      return new ThreadLocalSessionContext(this);
    }
    if ("managed".equals(impl)) {
      return new ManagedSessionContext(this);
    }
    try
    {
      Class implClass = ReflectHelper.classForName(impl);
      return ((CurrentSessionContext)implClass.getConstructor(new Class[] { SessionFactoryImplementor.class }).newInstance(new Object[] { this }));
    }
    catch (Throwable t)
    {
      log.error("Unable to construct current session context [" + impl + "]", t); }
    return null;
  }

可以看到,Hibernate会根据“hibernate.current_session_context_class”的属性值来决定创建哪一类上下文会话(Contextual Session),可以看看Hibernate的参考文档对这个属性的解释:“为当前Session的作用域选择一个自定义策略,可选的会话上下文有:jta|thread|managed|自定义类”。我们以thread类型会话来分析,ThreadLocalSessionContext会借助ThreadLocal实现每个线程有一个对应的session。

有了CurrentSessionContext,来看看getCurrentSession函数:

 public Session getCurrentSession()
    throws HibernateException
  {
    if (this.currentSessionContext == null) {
      throw new HibernateException("No CurrentSessionContext configured!");
    }
    return this.currentSessionContext.currentSession();
  }

它会通过CurrentSessionContext的currentSession()函数来获取session,针对ThreadLocalSessionContext,也即:

 public final org.hibernate.classic.Session currentSession()
    throws HibernateException
  {
    org.hibernate.classic.Session current = existingSession(this.factory);  //检查ThreadLocal中是否有session,有则直接返回,保证一个线程一个session
    if (current == null) {
      current = buildOrObtainSession(); //通过openSession创建一个新的session

      current.getTransaction().registerSynchronization(buildCleanupSynch());

      if (needsWrapping(current)) {
        current = wrap(current);  //包装session,主要是针对代理的情况
      }

      doBind(current, this.factory); //当然是把新建的session绑定到ThreadLocal中啦
    }
    return current;
  }

到了这里,基本就完成了,后面就是通过session执行各种数据操作以及事务管理之类的了。

 

 

如果未说明,本Blog中文章皆为原创文章,请尊重他人劳动,转载请注明: 转载自jmatrix

本文链接地址: hibernate源码分析——初始流程

(注:一般引用了,我都会添加引用,如果有侵权的请联系我)



This entry was posted in J2EE and tagged . Bookmark the permalink. Follow any comments here with the RSS feed for this post. Trackbacks are closed, but you can post a comment.