当前使用版本(必填,否则不予处理)
3.5.2
该问题是如何引起的?(确定最新版也有问题再提!!!)
自定义填充中获取请求上下文
@Override
public void insertFill(MetaObject metaObject) {
// 自定义填充
System.out.println(ServletUtils.getRequest());
System.out.println(JSONObject.toJSONString(ServletUtils.getRequest().getHeaderNames()));
System.out.println(JSONObject.toJSONString(ServletUtils.getRequest().getParameterNames()));
this.strictInsertFill(metaObject, tenantSysField, String.class, ServletUtils.getRequest().getHeader(tenantSysField));
}
异步线程装饰器:
@Override
public Runnable decorate(Runnable runnable) {
ServletRequestAttributes context = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
return () -> {
try {
RequestContextHolder.setRequestAttributes(context);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
};
}
报错信息
这两个不是null,但是空的[]
System.out.println(JSONObject.toJSONString(ServletUtils.getRequest().getHeaderNames()));
System.out.println(JSONObject.toJSONString(ServletUtils.getRequest().getParameterNames()));
Comment From: miemieYaho
那就是你代码问题,线程之间没同步数据
Comment From: yl-yue
@miemieYaho 抱歉,问题已定位,不是mybatis-puls清空了上下文,而是forest这个httpclient清空了上下文
异步线程上下文这个同步了的,上面提到的异步线程装饰器就是用来同步上下文的,只是上下文在异步方法中执行的forest请求时被清空了,而mybatis-puls的代码在forest后执行。
public interface TaskDecorator {
/**
* Decorate the given {@code Runnable}, returning a potentially wrapped
* {@code Runnable} for actual execution, internally delegating to the
* original {@link Runnable#run()} implementation.
* @param runnable the original {@code Runnable}
* @return the decorated {@code Runnable}
*/
Runnable decorate(Runnable runnable);
}
Comment From: yl-yue
抱歉,这个问题是Servlet已关闭的原因(调用 destroy() 方法),导致子线程获取的上下文为空。很多年前我已解决过此问题,并做了规范封装,但现在又忘了。。。在这记录下,目前采用MDC传递上下文,不用Servlet了,也不需要去阻塞Servlet.
贴一下以前的封装代码:
@AllArgsConstructor
public abstract class AbstractContextDecorator implements TaskDecorator {
protected AsyncProperties asyncProperties;
/**
* 启用 ServletAsyncContext,异步上下文最长生命周期(最大阻塞父线程多久)
* <p>用于阻塞父线程 Servlet 的关闭(调用 destroy() 方法),导致子线程获取的上下文为空</p>
*
* @param context 父线程上下文
* @param asyncProperties 异步属性配置
*/
protected void enableServletAsyncContext(ServletRequestAttributes context, AsyncProperties asyncProperties) {
if (!asyncProperties.isEnableServletAsyncContext()) {
return;
}
HttpServletRequest request = context.getRequest();
request.startAsync();
Object servletAsyncContextTimeoutMillis = request.getAttribute(AsyncProperties.SERVLET_ASYNC_CONTEXT_TIMEOUT_MILLIS);
if (servletAsyncContextTimeoutMillis == null) {
servletAsyncContextTimeoutMillis = asyncProperties.getServletAsyncContextTimeoutMillis();
}
request.getAsyncContext().setTimeout(Convert.toLong(servletAsyncContextTimeoutMillis));
}
/**
* 完成异步请求处理并关闭响应流
*
* @param context 父线程上下文
* @param asyncProperties 异步属性配置
*/
protected void completeServletAsyncContext(ServletRequestAttributes context, AsyncProperties asyncProperties) {
if (asyncProperties.isEnableServletAsyncContext()) {
context.getRequest().getAsyncContext().complete();
}
}
}
Comment From: morning-reading
我也是遇到这样问题,楼主这解决方案可以,能提供下代码吗?