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);