目前遇到个问题:
有一个rest接口是异步执行的,客户端请求,先验证参数。成功后就响应成功,而后丢到线程池异步执行任务。但是异步执行的时候需要保存userName。而之前的userName是通过RequestContextUtil获取当前用户request的header token取到的。
到现在变成异步执行,那么肯定就没了request。那么从哪儿取这个用户的session呢?
最开始因为是单线程的,非常简单。直接在响应客户端之前就存到缓存中,key是固定的。
之后线程池执行(单线程)的时候取这个固定的key即可。
慢慢的,发现不满足需求了,必须要弄成多线程。那么,如何拿到这个key呢?
我想到的方法是给线程设置名称,而名称就是key。
响应客户端之前存入缓存的key是userName,然后在new Task的时候把userName存入线程的final字段,在run方法中设置线程名称。之后就可以根据Thread.getCurrentThread().getName()获取到用户名,从而去缓存中读取用户session了
代码如下:
1.在rest接口service层参数验证后把session存入缓存
try {
RequestContextUtil.putCurrentSessionInUserInfoByAutoDeploy();//存放异步session
AutoDeployExcutor.submitTask(new AutoDeployTask(releaseDetail,
replicas),releaseDetail.getAppName());
} catch (Exception e) {
e.printStackTrace();
return ReturnUtil.format(ErrorCodeEnum.INTERNAL_ERROR);
}
/**
* 存放autoDeploy的用户信息
*/
public static String putCurrentSessionInUserInfoByAutoDeploy(){
try {
String Authentication = getRequestByCurrentContext().getHeader("Authentication");
UserLoginInfoVo userLoginInfoVo = JSONObject.toJavaObject(
authJson, UserLoginInfoVo.class);
//存入缓存
Cache.put(userLoginInfoVo.getName(), userLoginInfoVo);
return userLoginInfoVo.getName();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
第二步:在线程task里面设置线程名称
注意,在new Task()方法执行的时候还是可以获取到request的,所以无需把userName传入到构造参数中
public class AutoDeployTask implements Runnable{
private String finalUserName;
public AutoDeployTask(ReleaseDetail releaseDetail,Integer replicas) {
String userName = RequestContextUtil.getUserNameByCurrentContext();
this.finalUserName = userName;
}
@Override
public void run() {
logger.info(Thread.currentThread().getName());//pool-4-name
Thread.currentThread().setName(finalUserName);//设置线程名称 以便后续操作取出session
logger.info(Thread.currentThread().getName());//明辰晨
}
}
第三步:获取异步的session
public static UserLoginInfoVo getAsynUserInfoByAutoDeploy() {
//key是用户名-也是线程名
return DmsCache.get(Thread.currentThread().getName());
}