25
25
import org .springframework .transaction .support .TransactionSynchronizationManager ;
26
26
import org .springframework .ui .ModelMap ;
27
27
import org .springframework .web .context .request .WebRequest ;
28
- import org .springframework .web .context .request .async .AbstractDelegatingCallable ;
29
28
import org .springframework .web .context .request .async .AsyncWebRequestInterceptor ;
29
+ import org .springframework .web .context .request .async .AsyncWebUtils ;
30
+ import org .springframework .web .context .request .async .WebAsyncManager ;
31
+ import org .springframework .web .context .request .async .WebAsyncManager .AsyncThreadInitializer ;
30
32
31
33
/**
32
34
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
@@ -140,10 +142,19 @@ protected boolean isSingleSession() {
140
142
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
141
143
*/
142
144
public void preHandle (WebRequest request ) throws DataAccessException {
145
+
146
+ WebAsyncManager asyncManager = AsyncWebUtils .getAsyncManager (request );
147
+ String participateAttributeName = getParticipateAttributeName ();
148
+
149
+ if (asyncManager .hasConcurrentResult ()) {
150
+ if (asyncManager .applyAsyncThreadInitializer (participateAttributeName )) {
151
+ return ;
152
+ }
153
+ }
154
+
143
155
if ((isSingleSession () && TransactionSynchronizationManager .hasResource (getSessionFactory ())) ||
144
156
SessionFactoryUtils .isDeferredCloseActive (getSessionFactory ())) {
145
157
// Do not modify the Session: just mark the request accordingly.
146
- String participateAttributeName = getParticipateAttributeName ();
147
158
Integer count = (Integer ) request .getAttribute (participateAttributeName , WebRequest .SCOPE_REQUEST );
148
159
int newCount = (count != null ? count + 1 : 1 );
149
160
request .setAttribute (getParticipateAttributeName (), newCount , WebRequest .SCOPE_REQUEST );
@@ -157,6 +168,9 @@ public void preHandle(WebRequest request) throws DataAccessException {
157
168
applyFlushMode (session , false );
158
169
SessionHolder sessionHolder = new SessionHolder (session );
159
170
TransactionSynchronizationManager .bindResource (getSessionFactory (), sessionHolder );
171
+
172
+ AsyncThreadInitializer asyncThreadInitializer = createThreadInitializer (sessionHolder );
173
+ asyncManager .registerAsyncThreadInitializer (participateAttributeName , asyncThreadInitializer );
160
174
}
161
175
else {
162
176
// deferred close mode
@@ -165,44 +179,6 @@ public void preHandle(WebRequest request) throws DataAccessException {
165
179
}
166
180
}
167
181
168
- /**
169
- * Create a <code>Callable</code> to bind the <code>Hibernate</code> session
170
- * to the async request thread.
171
- */
172
- public AbstractDelegatingCallable getAsyncCallable (WebRequest request ) {
173
- String attributeName = getParticipateAttributeName ();
174
- if ((request .getAttribute (attributeName , WebRequest .SCOPE_REQUEST ) != null ) || !isSingleSession ()) {
175
- return null ;
176
- }
177
-
178
- final SessionHolder sessionHolder =
179
- (SessionHolder ) TransactionSynchronizationManager .getResource (getSessionFactory ());
180
-
181
- return new AbstractDelegatingCallable () {
182
- public Object call () throws Exception {
183
- TransactionSynchronizationManager .bindResource (getSessionFactory (), sessionHolder );
184
- getNext ().call ();
185
- return null ;
186
- }
187
- };
188
- }
189
-
190
- /**
191
- * Unbind the Hibernate <code>Session</code> from the main thread but leave
192
- * the <code>Session</code> open for further use from the async thread.
193
- */
194
- public void postHandleAsyncStarted (WebRequest request ) {
195
- String attributeName = getParticipateAttributeName ();
196
- if (request .getAttribute (attributeName , WebRequest .SCOPE_REQUEST ) == null ) {
197
- if (isSingleSession ()) {
198
- TransactionSynchronizationManager .unbindResource (getSessionFactory ());
199
- }
200
- else {
201
- throw new IllegalStateException ("Deferred close is not supported with async requests." );
202
- }
203
- }
204
- }
205
-
206
182
/**
207
183
* Flush the Hibernate <code>Session</code> before view rendering, if necessary.
208
184
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
@@ -232,18 +208,7 @@ public void postHandle(WebRequest request, ModelMap model) throws DataAccessExce
232
208
* @see org.springframework.transaction.support.TransactionSynchronizationManager
233
209
*/
234
210
public void afterCompletion (WebRequest request , Exception ex ) throws DataAccessException {
235
- String participateAttributeName = getParticipateAttributeName ();
236
- Integer count = (Integer ) request .getAttribute (participateAttributeName , WebRequest .SCOPE_REQUEST );
237
- if (count != null ) {
238
- // Do not modify the Session: just clear the marker.
239
- if (count > 1 ) {
240
- request .setAttribute (participateAttributeName , count - 1 , WebRequest .SCOPE_REQUEST );
241
- }
242
- else {
243
- request .removeAttribute (participateAttributeName , WebRequest .SCOPE_REQUEST );
244
- }
245
- }
246
- else {
211
+ if (!decrementParticipateCount (request )) {
247
212
if (isSingleSession ()) {
248
213
// single session mode
249
214
SessionHolder sessionHolder =
@@ -258,6 +223,34 @@ public void afterCompletion(WebRequest request, Exception ex) throws DataAccessE
258
223
}
259
224
}
260
225
226
+ public void afterConcurrentHandlingStarted (WebRequest request ) {
227
+ if (!decrementParticipateCount (request )) {
228
+ if (isSingleSession ()) {
229
+ TransactionSynchronizationManager .unbindResource (getSessionFactory ());
230
+ }
231
+ else {
232
+ throw new IllegalStateException ("Deferred close mode is not supported with async requests." );
233
+ }
234
+
235
+ }
236
+ }
237
+
238
+ private boolean decrementParticipateCount (WebRequest request ) {
239
+ String participateAttributeName = getParticipateAttributeName ();
240
+ Integer count = (Integer ) request .getAttribute (participateAttributeName , WebRequest .SCOPE_REQUEST );
241
+ if (count == null ) {
242
+ return false ;
243
+ }
244
+ // Do not modify the Session: just clear the marker.
245
+ if (count > 1 ) {
246
+ request .setAttribute (participateAttributeName , count - 1 , WebRequest .SCOPE_REQUEST );
247
+ }
248
+ else {
249
+ request .removeAttribute (participateAttributeName , WebRequest .SCOPE_REQUEST );
250
+ }
251
+ return true ;
252
+ }
253
+
261
254
/**
262
255
* Return the name of the request attribute that identifies that a request is
263
256
* already intercepted.
@@ -268,4 +261,15 @@ protected String getParticipateAttributeName() {
268
261
return getSessionFactory ().toString () + PARTICIPATE_SUFFIX ;
269
262
}
270
263
264
+ private AsyncThreadInitializer createThreadInitializer (final SessionHolder sessionHolder ) {
265
+ return new AsyncThreadInitializer () {
266
+ public void initialize () {
267
+ TransactionSynchronizationManager .bindResource (getSessionFactory (), sessionHolder );
268
+ }
269
+ public void reset () {
270
+ TransactionSynchronizationManager .unbindResource (getSessionFactory ());
271
+ }
272
+ };
273
+ }
274
+
271
275
}
0 commit comments