OpenSessionInView在每次Request请求的时候都打开一个Session放在ThreadLocal里面,该Session在Request期间一直可以使用,当View应用层的逻辑结束后,即filterChain.doFilter(request, response);完成后才会通过OpenSessionInViewFilter的closeSession方法关闭session。OpenSessionInViewFilter调用流程: request->open session并开始transaction->controller->View->结束transaction并close session.
public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
OncePerRequestFilter过滤器doFilter:
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { throw new ServletException( "OncePerRequestFilter just supports HTTP requests"); } HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName(); if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) { // Proceed without invoking this filter... filterChain.doFilter(request, response); } else { // Do invoke this filter... request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); try { doFilterInternal(httpRequest, httpResponse, filterChain); } finally { // Remove the "already filtered" request attribute for this // request. request.removeAttribute(alreadyFilteredAttributeName); } } }
调用了子类的doFilterInternal(httpRequest, httpResponse, filterChain);,也就是OpenSessionInViewFilter的doFilterInternal(httpRequest, httpResponse, filterChain);
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { SessionFactory sessionFactory = lookupSessionFactory(request);// ① boolean participate = false;// ② if (isSingleSession()) { // 配置文件中配置的 // <param-name>singleSession</param-name> // single session mode if (TransactionSynchronizationManager.hasResource(sessionFactory)) {// ③ // Do not modify the Session: just set the participate flag. participate = true; } else { logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter"); Session session = getSession(sessionFactory); TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));// ④ } } else { // deferred close mode if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) { // Do not modify deferred close: just set the participate flag. participate = true; } else { SessionFactoryUtils.initDeferredClose(sessionFactory); } } try { filterChain.doFilter(request, response);// ⑤ } finally { if (!participate) { if (isSingleSession()) { // ⑥ // single session mode SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager .unbindResource(sessionFactory); logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter"); closeSession(sessionHolder.getSession(), sessionFactory); } else { // deferred close mode SessionFactoryUtils.processDeferredClose(sessionFactory); } } } }
该方法都主要作用就是处理请求在当前线程共享同一个session。
① 获得一个SessionFactory
② 该布尔值用于标识过滤器结束时是否进行关闭session
public static boolean hasResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
return (value != null);
}
unwrapResourceIfNecessary:解除包装
③ 判断能否在当前线程中取得sessionFactory对象对应的session,第一次访问必然为false,如果有participate=true,意味着不关闭当前Session(具体看finally部分),以便整个请求中都使用同一个Session(例如:Action之间的转发,虽然过滤了多次,但还是同一个请求)
④在③中判断了当前线程中有没有对应都session,第一次请求肯定是没有都。自然而然就要创建一个,并绑定到当前线程中,SessionHolder是session的一层封装,里面有个存放session的map,而且是线程同步的Collections.synchronizedMap(new HashMap(1));
private final Map sessionMap = Collections.synchronizedMap(new HashMap(1));
核心方法是getValidatedSession 取得一个open状态下的session,并且取出后从map中移出.
public Session getValidatedSession() {
return getValidatedSession(DEFAULT_KEY);
}
public Session getValidatedSession(Object key) {
Session session = (Session) this.sessionMap.get(key);
// Check for dangling Session that's around but already closed.
// Effectively an assertion: that should never happen in practice.
// We'll seamlessly remove the Session here, to not let it cause
// any side effects.
if (session != null && !session.isOpen()) {
this.sessionMap.remove(key);
session = null;
}
return session;
}
⑤ 完整的请求处理
⑥ 当请求结束时,对于singleSession模式,要取消session的绑定,线程使用过后并不会销毁,因为web容器的线程是采用线程池机制的,所以最后一定要关闭session(closeSession);