Die*_*nia 23 spring spring-integration spring-aop
我有一个Web应用程序,它在一个独立的线程中运行Spring Integration逻辑.问题是,在某些时候,我的Spring Integration逻辑尝试使用请求范围的bean,然后我得到以下错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.tenantContext': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Caused by: 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Run Code Online (Sandbox Code Playgroud)
我设置了ContextLoaderListener:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)
我的Scoped Bean是这样注释的(因为我听说代理我的bean会有帮助):
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TenantContext implements Serializable {
Run Code Online (Sandbox Code Playgroud)
我正在做什么?如果是的话,我在这里错过了什么?如果不是,关于如何实现这一点的任何其他建议?
Dee*_*pak 13
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebMvcConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new HiddenHttpMethodFilter() };
}
**@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new RequestContextListener());
}**
}
Run Code Online (Sandbox Code Playgroud)
Gar*_*ell 11
您只能在运行请求的Web容器线程上使用请求(和会话)-scoped bean.
我假设线程正在等待SI流的异步回复?
如果是这样,您可以将请求范围的bean绑定到消息,可能在标头中或有效负载中的某个位置.
Thi*_*lak 10
使用RequestContextFilter并将属性threadContextInheritable设置为true.这使子线程继承父级的上下文,其中包含请求对象本身.还要确保执行程序不重用池中的线程,因为请求对象非常特定于该请求,并且不能跨各种请求共享.一个这样的执行器是SimpleAsyncTaskExecutor.
有关更多信息,请参阅范围'会话'对当前线程无效; IllegalStateException:未找到线程绑定请求.
对于春季启动2.4和Spring框架5,两者的RequestContextFilter并RequestContextListener没有为我工作。
挖掘到代码后,我发现DispatcherServlet将改写inheritable的RequestContextHolder通过设置RequestContextFilter或任何其他人,看到DispatcherServlet.processRequest和DispatcherServlet.initContextHolders。
所以解决方案非常简单,没有任何其他组件:
@Configuration
class whateverNameYouLike {
@Bean
DispatcherServlet dispatcherServlet() {
DispatcherServlet srvl = new DispatcherServlet();
srvl.setThreadContextInheritable(true);
return srvl;
}
}
Run Code Online (Sandbox Code Playgroud)
但请注意,该解决方案仅适用于当前请求线程创建的新线程,而不适用于任何线程池。
对于线程池情况,您可以依赖额外的包装器类吗?
public class InheritableRequestContextTaskWrapper {
private Map parentMDC = MDC.getCopyOfContextMap();
private RequestAttributes parentAttrs = RequestContextHolder.currentRequestAttributes();
public <T, R> Function<T, R> lambda1(Function<T, R> runnable) {
return t -> {
Map orinMDC = MDC.getCopyOfContextMap();
if (parentMDC == null) {
MDC.clear();
} else {
MDC.setContextMap(parentMDC);
}
RequestAttributes orinAttrs = null;
try {
orinAttrs = RequestContextHolder.currentRequestAttributes();
} catch (IllegalStateException e) {
}
RequestContextHolder.setRequestAttributes(parentAttrs, true);
try {
return runnable.apply(t);
} finally {
if (orinMDC == null) {
MDC.clear();
} else {
MDC.setContextMap(orinMDC);
}
if (orinAttrs == null) {
RequestContextHolder.resetRequestAttributes();
} else {
RequestContextHolder.setRequestAttributes(orinAttrs, true);
}
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它?
InheritableRequestContextTaskWrapper wrapper = new InheritableRequestContextTaskWrapper();
List<String> res = pool.submit(() -> ids.parallelStream().map(
wrapper.lambda1((String id) -> {
try {
// do something and return the result string
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error occurred in async tasks", e);
}
})).collect(Collectors.toList())).get();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
46409 次 |
| 最近记录: |