全国咨询/投诉热线:400-618-4000

Hibernate中如何获取与线程绑定的session源码解析

更新时间:2018年12月19日15时02分 来源:传智播客 浏览次数:

深入了解下ThreadLocalSessionContext如何做到将session和thread进行绑定.
     
首先,先来看下关键性的源码
      
而currentSessionContext对象又是在SessionFactoryImpl的构造方法中初始化的
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
public final class SessionFactoryImpl implements SessionFactoryImplementor{
    private final transient CurrentSessionContext currentSessionContext;
    public SessionFactoryImpl(final MetadataImplementor metadata, SessionFactoryOptions options) {
        LOG.debug( "Building session factory" );
        
        ...省略大量代码
        currentSessionContext = buildCurrentSessionContext();
        ...省略大量代码
    }
}
      
所以我们在这个buildCurrentSessionContext()方法中发现
      
好了~关键定位到了接下来我们就开始通过ThreadLocalSessionContext对象的创建开始,首先是执行的构造方法
[Java] 纯文本查看 复制代码
1
2
3
public ThreadLocalSessionContext(SessionFactoryImplementor factory) {
    super( factory );
}
      
查看父类AbstractCurrentSessionContext构造
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
public abstract class AbstractCurrentSessionContext implements CurrentSessionContext {
    private final SessionFactoryImplementor factory;
    protected AbstractCurrentSessionContext(SessionFactoryImplementor factory) {
        this.factory = factory;
    }
    .....
}
      
看到这里发现只是进行对象的保存操作而已~
      
回归ThreadLocalSessionContext
      
当然,开始分析流程吧~
      
Session current = existingSession( factory() );
      
第一眼看到的factory()源头
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
public abstract class AbstractCurrentSessionContext implements CurrentSessionContext {
    private final SessionFactoryImplementor factory;
    protected AbstractCurrentSessionContext(SessionFactoryImplementor factory) {
        this.factory = factory;
    }
    public SessionFactoryImplementor factory() {
        return factory;
    }
....
}
      
由此可出这个就是我们之前创建对象时通过构造传入的对象,接下来开始分析existingSession()方法
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
private static Session existingSession(SessionFactory factory) {
    final Map sessionMap = sessionMap();
    if ( sessionMap == null ) {
        return null;
    }
    return (Session) sessionMap.get( factory );
}
protected static Map sessionMap() {
    return CONTEXT_TL.get();
}
      
通过上面的源码我们分析出来核心在CONTEXT_TL对象,继续去找这个对象是什么时候创建的,最后发现是在类加载的时候就会创建
[Java] 纯文本查看 复制代码
1
private static final ThreadLocal<Map> CONTEXT_TL = new ThreadLocal<Map>();
      
ok~由此我们发现了这里其实使用的是ThreadLocal,这个是什么东西呢?将网上现成的解释直接拉过来了~~回头再开个章节单独细讲吧~
什么是ThreadLocal
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。
     
由此可知threadlocal可以为每个线程单独保存数据和获取互不影响~
      
而我们这里在当前线程中保存的是一个Map,这个Map又是什么呢?慢慢来~还是继续往下分析
      
      
第一次访问的话肯定什么都不存在,所以sessionMap一定为null,执行到最后,我们看到了doBind( current, factory() );
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
private static void doBind(org.hibernate.Session session, SessionFactory factory) {
    Map sessionMap = sessionMap();
    if ( sessionMap == null ) {
        sessionMap = new HashMap();
        CONTEXT_TL.set( sessionMap );
    }
    sessionMap.put( factory, session );
}
      
这doBind方法中,我们发现了又调用sessionMap()方法,这个方法我们也看过了,直接从ThreadLocal中获取,但是我们没存过又怎么能获取到呢?对吧,所以此时又会进入到为null的逻辑判断中,在这里我们总算是发现,我们在这创建了一个HashMap,并且把当前的hashMap保存到了CONTEXT_TL对象中,这样就保证了当前的map和当前线程进行绑定了~而做完这个操作后,我们又把传进来的factory和我们创建的session对象又保存到了我们的Map中,从而保证了通过我们的线程能够找到对应的map,而通过当前线程获取到的map,我们又找到了对应当前factory对应的session,从而实现了线程和当前数据库会话进行了绑定~


作者:传智播客JavaEE培训学院

首发:http://java.itcast.cn

javaee

python

web

ui

cloud

test

c

netmarket

pm

Linux

movies

robot

uids

北京校区

    14天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    20天免费试学

    基础班入门课程限时免费

    申请试学名额

    8天免费试学

    基础班入门课程限时免费

    申请试学名额

    20天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    0天免费试学

    基础班入门课程限时免费

    申请试学名额

    12天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    10天免费试学

    基础班入门课程限时免费

    申请试学名额