Hibernate源代码分析(一):设计属于我的SessionFactory和ConnectionProvider
过完五一长假,花了四天的时间来学习Hibernate框架的使用,作为门外汉,先是从sourceforg.net下载Hibernate3.2,先看官方文档,只有一个提纲,了解了一下各个包的结构,便开始根据Toturial实践,基本掌握了它的使用方法之后,盟生了实现自己的SessionFactory和ConnectionProvider的想法。
闲话少说,要实现我的SessionFactory和ConnectionProvider,不深入了解该体系结构是不行的,先从源代码分析开始:
Configuration.buildSessionFactory()方法获得一个SessionFactory,截取代码片段如下:
1
public
SessionFactory buildSessionFactory()
throws
HibernateException
{
2
3 return new SessionFactoryImpl(
4 this,
5 mapping,
6 settings,
7 getInitializedEventListeners()
8 );
9 }
2
3 return new SessionFactoryImpl(
4 this,
5 mapping,
6 settings,
7 getInitializedEventListeners()
8 );
9 }
上面的代码片断省略了读取Hibernate配置的代码,从这个我们可以知道,Configuration类buildSessionFactory()方法实际上返回了SessionFactory接口的实现SessionFactoryImpl。
当我们得到了一个SessionFactory接口的实现SessionFactoryImpl,就要调用它的getCurrentSession()方法来获得一个Session,接下来转到org.hibernate.impl.SessionFactoryImpl.java,来看看getCurrentSession()方法的实现,代码片段如下:
1
public
org.hibernate.classic.Session getCurrentSession()
throws
HibernateException
{
2 if ( currentSessionContext == null ) {
3 throw new HibernateException( "No CurrentSessionContext configured!" );
4 }
5 return currentSessionContext.currentSession();
6 }
2 if ( currentSessionContext == null ) {
3 throw new HibernateException( "No CurrentSessionContext configured!" );
4 }
5 return currentSessionContext.currentSession();
6 }
在该方法中,SessionFactoryImpl将获得Session的工作委托给了currentSessionContext.currentSession(),currentSessionContext为何物?其定义为:
org.hibernate.context.CurrentSessionContext;在SessionFactoryImpl的构造函数中,可以看到:
currentSessionContext
=
buildCurrentSessionContext();
马上追溯到buildCurrentSessionContext()方法,代码片段如下:
1
private
CurrentSessionContext buildCurrentSessionContext()
{
2 String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
3 // for backward-compatability
4 if ( impl == null && transactionManager != null ) {
5 impl = "jta";
6 }
7
8 if ( impl == null ) {
9 return null;
10 }
11 else if ( "jta".equals( impl ) ) {
12 if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
13 log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
14 }
15 return new JTASessionContext( this );
16 }
17 else if ( "thread".equals( impl ) ) {
18 return new ThreadLocalSessionContext( this );
19 }
20 else if ( "managed".equals( impl ) ) {
21 return new ManagedSessionContext( this );
22 }
23 else {
24 try {
25 Class implClass = ReflectHelper.classForName( impl );
26 return ( CurrentSessionContext ) implClass
27 .getConstructor( new Class[] { SessionFactoryImplementor.class } )
28 .newInstance( new Object[] { this } );
29 }
30 catch( Throwable t ) {
31 log.error( "Unable to construct current session context [" + impl + "]", t );
32 return null;
33 }
34 }
35 }
36
2 String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
3 // for backward-compatability
4 if ( impl == null && transactionManager != null ) {
5 impl = "jta";
6 }
7
8 if ( impl == null ) {
9 return null;
10 }
11 else if ( "jta".equals( impl ) ) {
12 if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
13 log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
14 }
15 return new JTASessionContext( this );
16 }
17 else if ( "thread".equals( impl ) ) {
18 return new ThreadLocalSessionContext( this );
19 }
20 else if ( "managed".equals( impl ) ) {
21 return new ManagedSessionContext( this );
22 }
23 else {
24 try {
25 Class implClass = ReflectHelper.classForName( impl );
26 return ( CurrentSessionContext ) implClass
27 .getConstructor( new Class[] { SessionFactoryImplementor.class } )
28 .newInstance( new Object[] { this } );
29 }
30 catch( Throwable t ) {
31 log.error( "Unable to construct current session context [" + impl + "]", t );
32 return null;
33 }
34 }
35 }
36
从这里可以发现,SessionFactoryImpl用反射实现了CurrentSessionContext接口的动态装配。
接下来,暂时将视线从SessionFactoryImpl移开,以org.hibernate.context.JTASessionContext为代表,看CurrentSessionContext接口是如何实现
的currentSession()方法的,打开org.hibernate.context.JTASessionContext.java,找到currentSession(),代码片段如下:
1
public
Session currentSession()
throws
HibernateException
{
2
3if ( currentSession == null ) {
4 currentSession = buildOrObtainSession();
5
6}
7
8return currentSession;
9}
2
3if ( currentSession == null ) {
4 currentSession = buildOrObtainSession();
5
6}
7
8return currentSession;
9}
转移到buildOrObtainSession()方法,
1
protected
Session buildOrObtainSession()
{
2 return factory.openSession(
3 null,
4 isAutoFlushEnabled(),
5 isAutoCloseEnabled(),
6 getConnectionReleaseMode()
7 );
8 }
2 return factory.openSession(
3 null,
4 isAutoFlushEnabled(),
5 isAutoCloseEnabled(),
6 getConnectionReleaseMode()
7 );
8 }
前面SessionFactoryImpl.buildCurrentSessionContext()方法有new JTASessionContext( this ),而此时的factory.openSessio()就是SessionFactoryImpl.openSessio()了。
将目光焦点回到org.hibernate.impl.SessionFactoryImpl.java, SessionFactoryImpl.openSessio()的实现如下:
1
private
SessionImpl openSession(
2 Connection connection,
3 boolean autoClose,
4 long timestamp,
5 Interceptor sessionLocalInterceptor
6 ) {
7 return new SessionImpl(
8 connection,
9 this,
10 autoClose,
11 timestamp,
12 sessionLocalInterceptor == null ? interceptor : sessionLocalInterceptor,
13 settings.getDefaultEntityMode(),
14 settings.isFlushBeforeCompletionEnabled(),
15 settings.isAutoCloseSessionEnabled(),
16 settings.getConnectionReleaseMode()
17 );
18 }
2 Connection connection,
3 boolean autoClose,
4 long timestamp,
5 Interceptor sessionLocalInterceptor
6 ) {
7 return new SessionImpl(
8 connection,
9 this,
10 autoClose,
11 timestamp,
12 sessionLocalInterceptor == null ? interceptor : sessionLocalInterceptor,
13 settings.getDefaultEntityMode(),
14 settings.isFlushBeforeCompletionEnabled(),
15 settings.isAutoCloseSessionEnabled(),
16 settings.getConnectionReleaseMode()
17 );
18 }