org.springframework.orm.hibernate4.support.OpenSessionInViewFilter

---恢复内容开始---

  1 /*
  2  * Copyright 2002-2014 the original author or authors.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package org.springframework.orm.hibernate4.support;
 18 
 19 import java.io.IOException;
 20 import javax.servlet.FilterChain;
 21 import javax.servlet.ServletException;
 22 import javax.servlet.http.HttpServletRequest;
 23 import javax.servlet.http.HttpServletResponse;
 24 
 25 import org.hibernate.FlushMode;
 26 import org.hibernate.HibernateException;
 27 import org.hibernate.Session;
 28 import org.hibernate.SessionFactory;
 29 
 30 import org.springframework.dao.DataAccessResourceFailureException;
 31 import org.springframework.orm.hibernate4.SessionFactoryUtils;
 32 import org.springframework.orm.hibernate4.SessionHolder;
 33 import org.springframework.transaction.support.TransactionSynchronizationManager;
 34 import org.springframework.web.context.WebApplicationContext;
 35 import org.springframework.web.context.request.async.WebAsyncManager;
 36 import org.springframework.web.context.request.async.WebAsyncUtils;
 37 import org.springframework.web.context.support.WebApplicationContextUtils;
 38 import org.springframework.web.filter.OncePerRequestFilter;
 39 
 40 /**
 41  * Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire
 42  * processing of the request. Intended for the "Open Session in View" pattern,
 43  * i.e. to allow for lazy loading in web views despite the original transactions
 44  * already being completed.
 45  *使用过滤器将请求的全部 hibernate session 绑定到线程。 用于“打开回话视图” 模式,
    允许在web 视图中延迟加载,尽管基本的事务已经完成,(虽然事务已经提交完成,但任然允许延迟加载数据?)
46 * <p>This filter makes Hibernate Sessions available via the current thread, which 47 * will be autodetected by transaction managers. It is suitable for service layer 48 * transactions via {@link org.springframework.orm.hibernate4.HibernateTransactionManager} 49 * as well as for non-transactional execution (if configured appropriately). 50 *这个过滤器使hibernaete session 可以通过当前线程,其将自动检测事务管理,适合于服务处通过HibernateTransactionManager 管理事务,以及非事务执行(如果适当配置)
    
51 * <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session, 52 * with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used 53 * in combination with service layer transactions that care for the flushing: The 54 * active transaction manager will temporarily change the flush mode to 55 * {@code FlushMode.AUTO} during a read-write transaction, with the flush 56 * mode reset to {@code FlushMode.NEVER} at the end of each transaction. 57 * 58 * <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that 59 * have not appeared before, through the use of a single Hibernate Session for the 60 * processing of an entire request. In particular, the reassociation of persistent 61 * objects with a Hibernate Session has to occur at the very beginning of request 62 * processing, to avoid clashes with already loaded instances of the same objects. 63 * 64 * <p>Looks up the SessionFactory in Spring's root web application context. 65 * Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml}; 66 * the default bean name is "sessionFactory". 67 * 68 * @author Juergen Hoeller 69 * @since 3.1 70 * @see #lookupSessionFactory 71 * @see OpenSessionInViewInterceptor 72 * @see OpenSessionInterceptor 73 * @see org.springframework.orm.hibernate4.HibernateTransactionManager 74 * @see org.springframework.transaction.support.TransactionSynchronizationManager 75 * @see org.hibernate.SessionFactory#getCurrentSession() 76 */ 77 public class OpenSessionInViewFilter extends OncePerRequestFilter { 78 79 public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory"; 80 81 private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME; 82 83 84 /** 85 * Set the bean name of the SessionFactory to fetch from Spring's 86 * root application context. Default is "sessionFactory". 87 * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME 88 */ 89 public void setSessionFactoryBeanName(String sessionFactoryBeanName) { 90 this.sessionFactoryBeanName = sessionFactoryBeanName; 91 } 92 93 /** 94 * Return the bean name of the SessionFactory to fetch from Spring's 95 * root application context. 96 */ 97 protected String getSessionFactoryBeanName() { 98 return this.sessionFactoryBeanName; 99 } 100 101 /** 102 * Returns "false" so that the filter may re-bind the opened Hibernate 103 * {@code Session} to each asynchronously dispatched thread and postpone 104 * closing it until the very last asynchronous dispatch.
      返回false 是因为这个filter 可以开启session的异步只读操作模式,延迟关闭它直到异步加载完成。
105 */ 106 @Override 107 protected boolean shouldNotFilterAsyncDispatch() { 108 return false; 109 } 110 111 /** 112 * Returns "false" so that the filter may provide a Hibernate 113 * {@code Session} to each error dispatches.
       返回false以便这个filter可以提供一个session的错误输出。
114 */ 115 @Override 116 protected boolean shouldNotFilterErrorDispatch() { 117 return false; 118 } 119 120 @Override 121 protected void doFilterInternal( 122 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 123 throws ServletException, IOException { 124      //通过指定的名称获取sessionFactory  125 SessionFactory sessionFactory = lookupSessionFactory(request); 126 boolean participate = false; 127     //通过当前的request请求获得web 异步管理器,如果没有异步管理器则创建一个并与request关联。 128 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        
        //返回一个请求的属性名称已用于识别其已经过滤。
129 String key = getAlreadyFilteredAttributeName();
130       //检测这个sessionFactory是否绑定到当前线程。 131 if (TransactionSynchronizationManager.hasResource(sessionFactory)) { 132 // Do not modify the Session: just set the participate flag. 133 participate = true; 134 } 135 else {
          //这个过滤器是否是异步执行的,因为一个filter是可以调用多个线程的单个请求的。
136 boolean isFirstRequest = !isAsyncDispatch(request); 137 if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) { 138 logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); 139 Session session = openSession(sessionFactory);
            //包装一个session以使下一句将其绑定到thread.
140 SessionHolder sessionHolder = new SessionHolder(session); 141 TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); 142          //实例化一个opensessionInViewFilter类专用的异步请求拦截器,从其类解释来看很有必要。 143 AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
            //将异步请求拦截器与reques关联
144 asyncManager.registerCallableInterceptor(key, interceptor);
            //延迟的请求
145 asyncManager.registerDeferredResultInterceptor(key, interceptor); 146 } 147 } 148 149 try { 150 filterChain.doFilter(request, response); 151 } 152 153 finally { 154 if (!participate) { 155 SessionHolder sessionHolder = 156 (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); 157 if (!isAsyncStarted(request)) { 158 logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 159 SessionFactoryUtils.closeSession(sessionHolder.getSession()); 160 } 161 } 162 } 163 } 164 165 /** 166 * Look up the SessionFactory that this filter should use, 167 * taking the current HTTP request as argument. 168 * <p>The default implementation delegates to the {@link #lookupSessionFactory()} 169 * variant without arguments. 170 * @param request the current request 171 * @return the SessionFactory to use 172 */ 173 protected SessionFactory lookupSessionFactory(HttpServletRequest request) { 174 return lookupSessionFactory(); 175 } 176 177 /** 178 * Look up the SessionFactory that this filter should use. 179 * <p>The default implementation looks for a bean with the specified name 180 * in Spring's root application context. 181 * @return the SessionFactory to use 182 * @see #getSessionFactoryBeanName 183 */ 184 protected SessionFactory lookupSessionFactory() { 185 if (logger.isDebugEnabled()) { 186 logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter"); 187 } 188 WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); 189 return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class); 190 } 191 192 /** 193 * Open a Session for the SessionFactory that this filter uses. 194 * <p>The default implementation delegates to the {@link SessionFactory#openSession} 195 * method and sets the {@link Session}'s flush mode to "MANUAL".
       打开session因为filter要使用,同时将session的事务提交模式设置为手动提交(MANUAL)
196 * @param sessionFactory the SessionFactory that this filter uses 197 * @return the Session to use 198 * @throws DataAccessResourceFailureException if the Session could not be created 199 * @see org.hibernate.FlushMode#MANUAL 200 */ 201 protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { 202 try { 203 Session session = sessionFactory.openSession(); 204 session.setFlushMode(FlushMode.MANUAL); 205 return session; 206 } 207 catch (HibernateException ex) { 208 throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); 209 } 210 } 211   
      
     /*检测前面获取的请求属性名是否已注册至异步管理器中,如果已经注册了,则通过绑定到当前线程的sessionFactory创建session*/  212 private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) { 213 if (asyncManager.getCallableInterceptor(key) == null) { 214 return false; 215 }
        
216 ((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession(); 217 return true; 218 } 219 220 }

---恢复内容结束---

原文地址:https://www.cnblogs.com/wangzhihua/p/4614828.html