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的意义
这次先到这里,下回就解决这些细节问题,那么入口和出口的大致流程就完事儿了```
上回大致把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的意义
这次先到这里,下回就解决这些细节问题,那么入口和出口的大致流程就完事儿了```
推荐阅读
-
深入解析vue 源码目录及构建过程分析
-
详解JAVAEE——SSH三大框架整合(spring+struts2+hibernate)
-
一个模仿oso的php论坛程序源码(之三)第1/2页
-
如何针对B2C网站做SEO诊断之案例分析
-
关于Yii2框架跑脚本时内存泄漏问题的分析与解决
-
B2C购物网站的购物车如何设计分析
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
Symfony2开发之控制器用法实例分析
-
go开源项目influxdb-relay源码分析(一)
-
AbstractQueuedSynchronizer源码分析(ReentrantLock锁的实现)