Spring对HibernateSession的管理之OpenSessionInViewFilter

  由于Java EE的学习进入到了一个重要的阶段——开始学习SSH框架(Struts2+Spring+Hibernate)了,在初步认识了框架的整合后,我对Spring是如何管理Session(Hibernate)抱有一些疑问。在进行了一些研究后有一些心得,在此记录下来,以便自己日后查询和供后来者作为借鉴。

  进入正题:

  首先我们打开org.springframework.orm.hibernate3.support.OpenSessionInViewFilter,看不出什么什么门道,连过滤器的doFilter方法都没有。很明显,它会调用父类的doFilter方法,而我们正是需要研究Spring是怎样通过过滤器来实现Session有效期的延长的(注意:Spring默认将Session与Request进程绑定,Request生命周期即Session能够存在的时长,所以在处理器处理请求后向JSP页面跳转时Session随着Request的生命周期而失效,以致页面无法使用Session)。

  那么我们马上进入OpenSessionInViewFilter的父类org.springframework.web.filter.OncePerRequestFilter看看(省略注释):

 1 public abstract class OncePerRequestFilter extends GenericFilterBean {
 2 
 3     public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
 4 
 5     public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
 6             throws ServletException, IOException {
 7 
 8         if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
 9             throw new ServletException("OncePerRequestFilter just supports HTTP requests");
10         }
11         HttpServletRequest httpRequest = (HttpServletRequest) request;
12         HttpServletResponse httpResponse = (HttpServletResponse) response;
13 
14         String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
15         if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {
16             filterChain.doFilter(request, response);
17         }
18         else {
19             request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
20             try {
21                 doFilterInternal(httpRequest, httpResponse, filterChain);
22             }
23             finally {
24                 request.removeAttribute(alreadyFilteredAttributeName);
25             }
26         }
27     }
28 
29     protected String getAlreadyFilteredAttributeName() {
30         String name = getFilterName();
31         if (name == null) {
32             name = getClass().getName();
33         }
34         return name + ALREADY_FILTERED_SUFFIX;
35     }
36 
37     protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
38         return false;
39     }
40 
41     protected abstract void doFilterInternal(
42             HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
43             throws ServletException, IOException;
44 
45 }

  从上面代码的15行到21行左右大家可以看出:这个方法进行了一个判断,看是否需要延长Session存在时间到整个请求响应过程,而实现延长时间的方法就是OpenSessionInViewFilter重写了的方法(省略部分注释):

  1 package org.springframework.orm.hibernate3.support;
  2 
  3 import java.io.IOException;
  4 import javax.servlet.FilterChain;
  5 import javax.servlet.ServletException;
  6 import javax.servlet.http.HttpServletRequest;
  7 import javax.servlet.http.HttpServletResponse;
  8 
  9 import org.hibernate.FlushMode;
 10 import org.hibernate.Session;
 11 import org.hibernate.SessionFactory;
 12 
 13 import org.springframework.dao.DataAccessResourceFailureException;
 14 import org.springframework.orm.hibernate3.SessionFactoryUtils;
 15 import org.springframework.orm.hibernate3.SessionHolder;
 16 import org.springframework.transaction.support.TransactionSynchronizationManager;
 17 import org.springframework.web.context.WebApplicationContext;
 18 import org.springframework.web.context.support.WebApplicationContextUtils;
 19 import org.springframework.web.filter.OncePerRequestFilter;
 20 
 21 public class OpenSessionInViewFilter extends OncePerRequestFilter {
 22 
 23     public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
 24 
 25 
 26     private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
 27 
 28     private boolean singleSession = true;
 29 
 30     private FlushMode flushMode = FlushMode.MANUAL;
 31 
 32     public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
 33         this.sessionFactoryBeanName = sessionFactoryBeanName;
 34     }
 35 
 36     protected String getSessionFactoryBeanName() {
 37         return this.sessionFactoryBeanName;
 38     }
 39 
 40     public void setSingleSession(boolean singleSession) {
 41         this.singleSession = singleSession;
 42     }
 43 
 44     protected boolean isSingleSession() {
 45         return this.singleSession;
 46     }
 47 
 48     public void setFlushMode(FlushMode flushMode) {
 49         this.flushMode = flushMode;
 50     }
 51 
 52     protected FlushMode getFlushMode() {
 53         return this.flushMode;
 54     }
 55 
 56 
 57     @Override
 58     protected void doFilterInternal(
 59             HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
 60             throws ServletException, IOException {
 61 
 62         SessionFactory sessionFactory = lookupSessionFactory(request);
 63         boolean participate = false;
 64 
 65         if (isSingleSession()) {
 66             // single session mode
 67             if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
 68                 // Do not modify the Session: just set the participate flag.
 69                 participate = true;
 70             }
 71             else {
 72                 logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
 73                 Session session = getSession(sessionFactory);
 74                 TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
 75             }
 76         }
 77         else {
 78             // deferred close mode
 79             if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
 80                 // Do not modify deferred close: just set the participate flag.
 81                 participate = true;
 82             }
 83             else {
 84                 SessionFactoryUtils.initDeferredClose(sessionFactory);
 85             }
 86         }
 87 
 88         try {
 89             filterChain.doFilter(request, response);
 90         }
 91 
 92         finally {
 93             if (!participate) {
 94                 if (isSingleSession()) {
 95                     // single session mode
 96                     SessionHolder sessionHolder =
 97                             (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
 98                     logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
 99                     closeSession(sessionHolder.getSession(), sessionFactory);
100                 }
101                 else {
102                     // deferred close mode
103                     SessionFactoryUtils.processDeferredClose(sessionFactory);
104                 }
105             }
106         }
107     }
108 
109     protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
110         return lookupSessionFactory();
111     }
112 
113     protected SessionFactory lookupSessionFactory() {
114         if (logger.isDebugEnabled()) {
115             logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
116         }
117         WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
118         return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
119     }
120 
121     protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
122         Session session = SessionFactoryUtils.getSession(sessionFactory, true);
123         FlushMode flushMode = getFlushMode();
124         if (flushMode != null) {
125             session.setFlushMode(flushMode);
126         }
127         return session;
128     }
129 
130     protected void closeSession(Session session, SessionFactory sessionFactory) {
131         SessionFactoryUtils.closeSession(session);
132     }
133 
134 }

  这里面org.springframework.orm.hibernate3.SessionFactoryUtils拥有很重要的地位,其重要一个字段如下:

    ThreadLocal<Map<SessionFactory, Set<Session>>> deferredCloseHolder =
   new NamedThreadLocal<Map<SessionFactory, Set<Session>>>("Hibernate Sessions registered for deferred close")

  另外org.springframework.transaction.support.TransactionSynchronizationManager也是很为重要:

    ThreadLocal<Map<Object, Object>> resources =
   new NamedThreadLocal<Map<Object, Object>>("Transactional resources") 及其他属性和方法与上面SessionFactoryUtils中的属性和方法一起,在OpenSessionInViewFilter#doFilterInternal方法中将Session绑定到ThreadLocal,在整个请求响应过程完成后关闭Session。

  

  也就是说:原本Spring是将Session绑定到Request所在线程里,而使用了OpenSessionInViewFilter过滤器后,会将Session绑定到当前进程中

  

  也是最近越来越烦躁,总是不能将整篇博文做到完整,本文章中的所有内容都可以在网络上搜索得到,扩展的知识却没来得及添加进来。

  另外,本篇博文所用资源src.zip

 

 

 欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

 或者通过QQ与我联系:点击这里给我发消息

 (最后编辑时间2012-10-09 22:59:36)

  

posted @ 2012-10-09 23:01  云中双月  阅读(4050)  评论(0编辑  收藏  举报