英文:
java.lang.IllegalStateException: No thread-bound request found when using RequestContextHolder.currentRequestAttributes() in async aspect
问题
我有以下方面,由于某些原因,您可以在[这里][1]看到,不得不在如下所示的方面方法上使用`@EnableAsync`和`@Async`:
@Aspect
@Component
@EnableAsync
public class ApiCallLogAspect {
@Async
@AfterReturning(value = "within(com.example..*.web.rest.api..*)", returning = "returnValue")
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
System.out.println(request.getHeader("authorization"));
}
}
现在,我遇到了这个异常:
java.lang.IllegalStateException: 找不到线程绑定的请求:您是否在实际的web请求之外引用了请求属性,或者在最初接收请求的线程之外处理请求?如果您实际上在web请求内部操作但仍然收到此消息,则可能是因为您的代码在DispatcherServlet之外运行:在这种情况下,请使用RequestContextListener或RequestContextFilter来公开当前请求。
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at com.example.web.rest.api.ApiCallLogAspect.endpointAfterReturning(ApiCallLogAspect.java:40) ~[classes/:na]
at com.example.web.rest.api.ApiCallLogAspect$$FastClassBySpringCGLIB$$f034ee12.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_162]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_162]
我该如何解决这个问题?是否有一种方法可以从...
注意:根据您的要求,我已经完成了中文翻译,代码部分没有翻译。如果您需要更多帮助,请随时提问。
英文:
I have this below aspect and for some reasons that you can see here, had to use @EnableAsync
and @Async
over aspect method as you can see below:
@Aspect
@Component
@EnableAsync
public class ApiCallLogAspect {
@Async
@AfterReturning(value = ("within(com.example..*.web.rest.api..*)"), returning = "returnValue")
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
System.out.println(request.getHeader("authorization"));
}
}
Now, i get this exception:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at com.example.web.rest.api.ApiCallLogAspect.endpointAfterReturning(ApiCallLogAspect.java:40) ~[classes/:na]
at com.example.web.rest.api.ApiCallLogAspect$$FastClassBySpringCGLIB$$f034ee12.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_162]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_162]
How can i solve this? is there a way to get request headers from
答案1
得分: 2
我通过以下更改解决了问题,结合了 @M.Deinum 的评论:
public class ThreadContextHolder {
private ThreadContextHolder() {
}
private static final ThreadLocal<Map<String, Object>> ctx = new ThreadLocal<>();
public static Map<String, Object> getContext() {
return ctx.get();
}
public static void setContext(Map<String, Object> attrs) {
ctx.set(attrs);
}
public static void removeContext() {
ctx.remove();
}
}
然后将 `taskExecutor` 注入到 `ApiCallLogAspect` 类中:
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(
runnable -> {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Map<String, Object> headers = new HashMap<>();
for (String header : Collections.list(request.getHeaderNames())) {
headers.put(header, request.getHeader(header));
}
return () -> {
try {
ThreadContextHolder.setContext(headers);
runnable.run();
} finally {
ThreadContextHolder.removeContext();
}
};
});
executor.initialize();
return executor;
}
然后将 `endpointAfterReturning` 方法更改为:
@Async
@AfterReturning(value = "within(com.example..*.web.rest.api..*)", returning = "returnValue")
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
Map<String, String> headers = new HashMap<>();
ThreadContextHolder.getContext().forEach((s, o) -> headers.put(s, o.toString()));
System.out.println(headers.get("authorization"));
}
现在,一切都正常工作。如果这个解决方案有问题,请通知我。
英文:
I solved the problem by these changes below with @M.Deinum comments:
public class ThreadContextHolder {
private ThreadContextHolder() {
}
private static final ThreadLocal<Map<String, Object>> ctx = new ThreadLocal<>();
public static Map<String, Object> getContext() {
return ctx.get();
}
public static void setContext(Map<String, Object> attrs) {
ctx.set(attrs);
}
public static void removeContext() {
ctx.remove();
}
}
and then inject taskExecutor
to ApiCallLogAspect
class:
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(
runnable -> {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Map<String, Object> headers = new HashMap<>();
for (String header : Collections.list(request.getHeaderNames())) {
headers.put(header, request.getHeader(header));
}
return () -> {
try {
ThreadContextHolder.setContext(headers);
runnable.run();
} finally {
ThreadContextHolder.removeContext();
}
};
});
executor.initialize();
return executor;
}
and then change endpointAfterReturning
method to it:
@Async
@AfterReturning(value = ("within(com.example..*.web.rest.api..*)"), returning = "returnValue")
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
Map<String, String> headers = new HashMap<>();
ThreadContextHolder.getContext().forEach((s, o) -> headers.put(s, o.toString()));
System.out.println(headers.get("authorization"));
}
Now, everything works fine. If this solution has a problem please notify to me.
答案2
得分: 1
I solved this issue by including the following annotations in the pointcut expression
@Pointcut("within(@org.springframework.stereotype.Repository )"
+ " || within(@org.springframework.stereotype.Service )"
+ "|| within(@org.springframework.stereotype.Component )"
+ " || within(@org.springframework.web.bind.annotation.RestController )")
public void springBeanPointcut() {
}
and assign it to advice as below
@Around("myPointcut() && springBeanPointcut()")
public Object applicationLogger(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}
英文:
I solved this issue by including the following annotations in the pointcut expression
@Pointcut("within(@org.springframework.stereotype.Repository *)"
+ " || within(@org.springframework.stereotype.Service *)"
+ "|| within(@org.springframework.stereotype.Component *)"
+ " || within(@org.springframework.web.bind.annotation.RestController *)")
public void springBeanPointcut() {
}
and assign it to advice as below
@Around("myPointcut() && springBeanPointcut()")
public Object applicationLogger(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论