我找到了一个有效的解决方案并消除了错误。因为我不认为这真的很干净,所以我希望有更多的答案,但万一它对某人有帮助:
首先我添加了这个类。它创建了一个自定义且非常简单的 RequestAttributes-Implementation,使我们能够使属性保持活动的时间比通常更长:
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
public class AsyncRequestScopeAttr extends ServletRequestAttributes {
private Map<String, Object> requestAttributeMap = new HashMap<>();
public AsyncRequestScopeAttr(HttpServletRequest request) {
super(request);
}
@Override
public void requestCompleted() {
//keep the request active, normally here this.requestActive would be set to false -> we do that in the completeRequest()-method which is manually called after the async method is done
}
/**
* This method should be called after your async method is finished. Normally it is called when the
* request completes but since our async method can run longer we call it manually afterwards
*/
public void completeRequest() {
super.requestCompleted();
}
@Override
public Object getAttribute(String name, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
return this.requestAttributeMap.get(name);
}
return null;
}
@Override
public void setAttribute(String name, Object value, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST){
this.requestAttributeMap.put(name, value);
}
}
@Override
public void removeAttribute(String name, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
this.requestAttributeMap.remove(name);
}
}
@Override
public String[] getAttributeNames(int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
return this.requestAttributeMap.keySet().toArray(new String[0]);
}
return new String[0];
}
@Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
// Not Supported
}
@Override
public Object resolveReference(String key) {
// Not supported
return null;
}
@Override
public String getSessionId() {
return null;
}
@Override
public Object getSessionMutex() {
return null;
}
@Override
protected void updateAccessedSessionAttributes() {
}
}
然后在调用async方法之前的RestController中:
@Autowired
//this is the service that contains the async-method
OtherService otherService;
public void someFunctionWithinTheMainRequestThread(){
otherService.asyncMethod(getIndependentRequestAttributesForAsync());
}
private RequestAttributes getIndependentRequestAttributesForAsync(){
RequestAttributes requestAttributes = new AsyncRequestScopeAttr(((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest());
for (String attributeName : RequestContextHolder.getRequestAttributes().getAttributeNames(RequestAttributes.SCOPE_REQUEST)) {
RequestContextHolder.getRequestAttributes().setAttribute(attributeName, RequestContextHolder.getRequestAttributes().getAttribute(attributeName, RequestAttributes.SCOPE_REQUEST), RequestAttributes.SCOPE_REQUEST);
}
return requestAttributes;
}
然后在异步函数中:
public class OtherService {
@Async
@Transactional(readOnly=true)
public void asyncMethod(RequestAttributes context) {
//set the RequestAttributes for this thread
RequestContextHolder.setRequestAttributes(context);
// do your thing .... linkTo() etc.
//cleanup
((AsyncRequestScopeAttr)context).completeRequest();
RequestContextHolder.resetRequestAttributes();
}
}