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 }

 

---恢復內容結束---


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM