java.lang.IllegalStateException: No thread-bound request found when using RequestContextHolder.currentRequestAttributes() in async aspect

huangapple go评论78阅读模式
英文:

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 = (&quot;within(com.example..*.web.rest.api..*)&quot;), returning = &quot;returnValue&quot;)
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
System.out.println(request.getHeader(&quot;authorization&quot;));
}
}

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(&lt;generated&gt;) ~[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&lt;Map&lt;String, Object&gt;&gt; ctx = new ThreadLocal&lt;&gt;();
public static Map&lt;String, Object&gt; getContext() {
return ctx.get();
}
public static void setContext(Map&lt;String, Object&gt; 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 -&gt; {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Map&lt;String, Object&gt; headers = new HashMap&lt;&gt;();
for (String header : Collections.list(request.getHeaderNames())) {
headers.put(header, request.getHeader(header));
}
return () -&gt; {
try {
ThreadContextHolder.setContext(headers);
runnable.run();
} finally {
ThreadContextHolder.removeContext();
}
};
});
executor.initialize();
return executor;
}

and then change endpointAfterReturning method to it:

@Async
@AfterReturning(value = (&quot;within(com.example..*.web.rest.api..*)&quot;), returning = &quot;returnValue&quot;)
public void endpointAfterReturning(JoinPoint p, Object returnValue) throws InterruptedException {
Map&lt;String, String&gt; headers = new HashMap&lt;&gt;();
ThreadContextHolder.getContext().forEach((s, o) -&gt; headers.put(s, o.toString()));
System.out.println(headers.get(&quot;authorization&quot;));
}

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(&quot;within(@org.springframework.stereotype.Repository *)&quot;
+ &quot; || within(@org.springframework.stereotype.Service *)&quot;
+ &quot;|| within(@org.springframework.stereotype.Component *)&quot;
+ &quot; || within(@org.springframework.web.bind.annotation.RestController *)&quot;)
public void springBeanPointcut() {
}

and assign it to advice as below

 	@Around(&quot;myPointcut() &amp;&amp; springBeanPointcut()&quot;)
public Object applicationLogger(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}

huangapple
  • 本文由 发表于 2020年7月27日 21:46:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63116739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定