@ -16,7 +16,12 @@
@@ -16,7 +16,12 @@
package org.springframework.web.context.request ;
import java.util.Enumeration ;
import java.util.HashMap ;
import java.util.Map ;
import io.micrometer.context.ThreadLocalAccessor ;
import jakarta.servlet.http.HttpServletRequest ;
import org.springframework.lang.Nullable ;
@ -26,6 +31,7 @@ import org.springframework.lang.Nullable;
@@ -26,6 +31,7 @@ import org.springframework.lang.Nullable;
* { @link RequestAttributes } propagation .
*
* @author Tadaya Tsuyukubo
* @author Rossen Stoyanchev
* @since 6 . 2
* /
public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor < RequestAttributes > {
@ -44,7 +50,11 @@ public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor
@@ -44,7 +50,11 @@ public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor
@Override
@Nullable
public RequestAttributes getValue ( ) {
return RequestContextHolder . getRequestAttributes ( ) ;
RequestAttributes request = RequestContextHolder . getRequestAttributes ( ) ;
if ( request instanceof ServletRequestAttributes sra & & ! ( sra instanceof SnapshotServletRequestAttributes ) ) {
request = new SnapshotServletRequestAttributes ( sra ) ;
}
return request ;
}
@Override
@ -57,4 +67,82 @@ public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor
@@ -57,4 +67,82 @@ public class RequestAttributesThreadLocalAccessor implements ThreadLocalAccessor
RequestContextHolder . resetRequestAttributes ( ) ;
}
/ * *
* ServletRequestAttributes that takes another instance , and makes a copy of the
* request attributes at present to provides extended read access during async
* handling when the DispatcherServlet has exited from the initial REQUEST dispatch
* and marked the request { @link ServletRequestAttributes # requestCompleted ( ) } .
* < p > Note that beyond access to request attributes , here is no attempt to support
* setting or removing request attributes , nor to access session attributes after
* the initial REQUEST dispatch has exited .
* /
private static final class SnapshotServletRequestAttributes extends ServletRequestAttributes {
private final ServletRequestAttributes delegate ;
private final Map < String , Object > attributeMap ;
public SnapshotServletRequestAttributes ( ServletRequestAttributes requestAttributes ) {
super ( requestAttributes . getRequest ( ) , requestAttributes . getResponse ( ) ) ;
this . delegate = requestAttributes ;
this . attributeMap = getAttributes ( requestAttributes . getRequest ( ) ) ;
}
private static Map < String , Object > getAttributes ( HttpServletRequest request ) {
Map < String , Object > map = new HashMap < > ( ) ;
Enumeration < String > names = request . getAttributeNames ( ) ;
while ( names . hasMoreElements ( ) ) {
String name = names . nextElement ( ) ;
map . put ( name , request . getAttribute ( name ) ) ;
}
return map ;
}
// Delegate methods that check isRequestActive()
@Nullable
@Override
public Object getAttribute ( String name , int scope ) {
if ( scope = = RequestAttributes . SCOPE_REQUEST & & ! this . delegate . isRequestActive ( ) ) {
return this . attributeMap . get ( name ) ;
}
try {
return this . delegate . getAttribute ( name , scope ) ;
}
catch ( IllegalStateException ex ) {
if ( scope = = RequestAttributes . SCOPE_REQUEST ) {
return this . attributeMap . get ( name ) ;
}
throw ex ;
}
}
@Override
public String [ ] getAttributeNames ( int scope ) {
if ( scope = = RequestAttributes . SCOPE_REQUEST & & ! this . delegate . isRequestActive ( ) ) {
return this . attributeMap . keySet ( ) . toArray ( new String [ 0 ] ) ;
}
try {
return this . delegate . getAttributeNames ( scope ) ;
}
catch ( IllegalStateException ex ) {
if ( scope = = RequestAttributes . SCOPE_REQUEST ) {
return this . attributeMap . keySet ( ) . toArray ( new String [ 0 ] ) ;
}
throw ex ;
}
}
@Override
public void setAttribute ( String name , Object value , int scope ) {
this . delegate . setAttribute ( name , value , scope ) ;
}
@Override
public void removeAttribute ( String name , int scope ) {
this . delegate . removeAttribute ( name , scope ) ;
}
}
}