欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hibernate源码分析2

程序员文章站 2022-06-11 12:02:30
...
再扯二句蛋:距离上一次写博客已经过了将近半个月了,因为公司的活比较多,一直没有时间研究(实际上一直都有很多活),元旦还出去浪了一圈,这个周末再来写一点`
上回大致把hibernate的启动加载配置的过程说了一遍,说到了XClass和保存的集合MetadataSourceQueue,这两个东西我暂时不想说(其实没有研究明白,怕说不好),我觉得研究hibernate框架可以从两头开始,一个是入口,也就是上一篇的启动加载过程,一个是出口,也就是我们经常调用的接口方法和类,今天从出口来讲一下,以后再将两头串起来。。。

我们常使用的接口要算是SessionFactory 了:
SessionFactory factory = cfg.buildSessionFactory();
buildSessionFactory中实际上返回的对象是SessionFactoryImpl,而SessionFactoryImpl实现了SessionFactoryImplementor接口,而SessionFactoryImplementor这个接口又继承了SessionFactory这个接口,SessionFactoryImpl实际上就是一个SessionFactory,为何需要在他们中间横插一个SessionFactoryImplementor?研究!

实际上这个不带参数的buildSessionFactory()最终调用的是带参的buildSessionFactory(ServiceRegistry serviceRegistry),这个方法返回了最终的SessionFactoryImp:
new SessionFactoryImpl(
    this,
    mapping,
    serviceRegistry,
    settings,
    sessionFactoryObserver
   );

接着往下走,话说SessionFactory的getCurrentSession方法将返回我们最终使用的Session,且看SessionFactory中的getCurrentSession方法做了什么,上源码:
if ( currentSessionContext == null ) {
   throw new HibernateException( "No CurrentSessionContext configured!" );
  }
  return currentSessionContext.currentSession();
显然是用了currentSessionContext.currentSession() 这个东西来获得的,其实 SeesionFactory本身并没有Session,而是用的是currentSessionContext 的Session!那么currentSessionContext 是啥?就是CurrentSessionContext类,从名字上就知道意思了:当前Session上下文,做了这么久的代码,上下文的意思应该知道吧
好了,再看看currentSessionContext 到底是何方神圣:currentSessionContext = buildCurrentSessionContext();
buildCurrentSessionContext这个方法做了啥?上源码:
private CurrentSessionContext buildCurrentSessionContext() {
  String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
  // for backward-compatibility
  if ( impl == null ) {
   if ( canAccessTransactionManager() ) {
    impl = "jta";
   }
   else {
    return null;
   }
  }
  if ( "jta".equals( impl ) ) {
   if ( ! transactionFactory().compatibleWithJtaSynchronization() ) {
    LOG.autoFlushWillNotWork();
   }
   return new JTASessionContext( this );
  }
  else if ( "thread".equals( impl ) ) {
   return new ThreadLocalSessionContext( this );
  }
  else if ( "managed".equals( impl ) ) {
   return new ManagedSessionContext( this );
  }
  else {
   try {
    Class implClass = serviceRegistry.getService( ClassLoaderService.class ).classForName( impl );
    return ( CurrentSessionContext ) implClass
      .getConstructor( new Class[] { SessionFactoryImplementor.class } )
      .newInstance( this );
   }
   catch( Throwable t ) {
    LOG.unableToConstructCurrentSessionContext( impl, t );
    return null;
   }
  }
}
看到没有: String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );回去试着去获取我们配置的信息
(题外话,配置的获取
  this.properties = new Properties();
  this.properties.putAll( cfg.getProperties() );

Environment.CURRENT_SESSION_CONTEXT_CLASS是 :public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";(在AvailableSettings中)
题外话:Environment implements AvailableSettings用来表示各种配置常量,这里的Environment 是hibernate自己的类,不是org.omg.CORBA.Environment !
看,如果我们再配置文件中将hibernate.current_session_context_class配置成thread就是返回的是ThreadLocalSessionContext(线程绑定的上下文),如果我们啥都不配的话,默认就是JTASessionContext(JTA的上下文),至于线程和JTA的含义,就属于另外讨论的话题了,有时间再研究
ok,假设我们就啥都没有配吧,就用的是JTASessionContext吧,顺着这个线走下去吧(解决主要矛盾嘛),那么肯定要来看看JTASessionContext的源码咯!首先我们很快就会发现各个SessionContext都会继承自一个抽象类:AbstractCurrentSessionContext,而AbstractCurrentSessionContext则是AbstractCurrentSessionContext implements CurrentSessionContext,
然后当然首要的是currentSession方法了,上源码:
@Override
public Session currentSession() throws HibernateException {
  final JtaPlatform jtaPlatform = factory().getServiceRegistry().getService( JtaPlatform.class );
  final TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
  if ( transactionManager == null ) {
   throw new HibernateException( "No TransactionManagerLookup specified" );
  }
  Transaction txn;
  try {
   txn = transactionManager.getTransaction();
   if ( txn == null ) {
    throw new HibernateException( "Unable to locate current JTA transaction" );
   }
   if ( !JtaStatusHelper.isActive( txn.getStatus() ) ) {
    // We could register the session against the transaction even though it is
    // not started, but we'd have no guarantee of ever getting the map
    // entries cleaned up (aside from spawning threads).
    throw new HibernateException( "Current transaction is not in progress" );
   }
  }
  catch ( HibernateException e ) {
   throw e;
  }
  catch ( Throwable t ) {
   throw new HibernateException( "Problem locating/validating JTA transaction", t );
  }
  final Object txnIdentifier = jtaPlatform.getTransactionIdentifier( txn );
  Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );
  if ( currentSession == null ) {
   currentSession = buildOrObtainSession();
   try {
    txn.registerSynchronization( buildCleanupSynch( txnIdentifier ) );
   }
   catch ( Throwable t ) {
    try {
     currentSession.close();
    }
    catch ( Throwable ignore ) {
     LOG.debug( "Unable to release generated current-session on failed synch registration", ignore );
    }
    throw new HibernateException( "Unable to register cleanup Synchronization with TransactionManager" );
   }
   currentSessionMap.put( txnIdentifier, currentSession );
  }
  else {
   validateExistingSession( currentSession );
  }
  return currentSession;
}

其中,factory()是父类(AbstractCurrentSessionContext )的方法,只是:
public SessionFactoryImplementor factory() {
  return factory;
}
factory而已,这个factory是啥??
还记得SessionFactoryImp中buildCurrentSessionContext方法的return new JTASessionContext( this );吗?这个factory就是this(SessionFactoryImp实例)
final JtaPlatform jtaPlatform = factory().getServiceRegistry().getService( JtaPlatform.class );中 factory().getServiceRegistry()返回的是SessionFactoryImp的变量serviceRegistry,何处来的?
还记得我们在Configuration中new SessionFactoryImp的时候吗?
new SessionFactoryImpl(
    this,
    mapping,
    serviceRegistry,
    settings,
    sessionFactoryObserver
   )

上述的的这个不带参数的buildSessionFactory()最终调用的是带参的buildSessionFactory(ServiceRegistry serviceRegistry)的调用之前buildSessionFactory方法中做了:
final ServiceRegistry serviceRegistry =  new ServiceRegistryBuilder()
    .applySettings( properties )
    .buildServiceRegistry();
applySettings( properties )是将hibernate.properties产生的Properties对象传递给ServiceRegistryBuilder,而buildServiceRegistry方法则是发生事情的地方:
public ServiceRegistry buildServiceRegistry() {
  Map<?,?> settingsCopy = new HashMap();
  settingsCopy.putAll( settings );
  Environment.verifyProperties( settingsCopy );
  ConfigurationHelper.resolvePlaceHolders( settingsCopy );
  for ( Integrator integrator : bootstrapServiceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
   if ( ServiceContributingIntegrator.class.isInstance( integrator ) ) {
    ServiceContributingIntegrator.class.cast( integrator ).prepareServices( this );
   }
  }
  return new StandardServiceRegistryImpl( bootstrapServiceRegistry, initiators, providedServices, settingsCopy );
}
这就是我们得到SessionFactory的大致过程,其中的几个细节值得研究:
1:我们只是知道了要传入ServiceRegistry ,那是做啥的?
2:SessionFactoryImplementor的意义
这次先到这里,下回就解决这些细节问题,那么入口和出口的大致流程就完事儿了```