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

      

    认真你就输了,一直认真你就赢了!
  • 相关阅读:
    emacs command
    emacs format
    attach
    虚拟ip
    emacs redo
    mariadb
    unsafe
    select, poll, epoll
    03基于python玩转人工智能最火框架之TensorFlow介绍
    03SQL语句
  • 原文地址:https://www.cnblogs.com/Johness/p/2717577.html
Copyright © 2020-2023  润新知