Dubbo在使用RpcContext.getContext()传递参数时,因为参数的生命周期。所以只能调用一次,如果在方法中出现了连续调用两次的情况,则会出现获取不到参数的情况。
实际场景在sass类项目里比较常见,经常需要传递区分不同用户的关键字传递。
会出现问题的方法 例如:
在一个方法里,连续两次向服务端发起请求,则服务端在执行时只能获取一次参数。
解决办法:
1)在restkeeper_service_common工程中定义一个自定义dubbo过滤器
@Activate
@Slf4j
public class DubboConsumerContextFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext.getContext().setAttachment("shopId", TenantContext.getShopId());
return invoker.invoke(invocation);
}
}
修改配置文件
dubbo:
consumer:
filter: dubboConsumerContextFilter
dubboConsumerContextFilter=com.restkeeper.dubbo.DubboConsumerContextFilter
使用自定义的工具类
import java.util.LinkedHashMap;
import java.util.Map;
public class TenantContext {
static ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal<Map<String, Object>>(){
@Override
protected Map<String, Object> initialValue() {
return new LinkedHashMap<String, Object>();
}
};
public static void addAttachment(String key, Object value){
threadLocal.get().put(key,value);
}
public static void addAttachments(Map<String, Object> map){
threadLocal.get().putAll(map);
}
public static Map<String, Object> getAttachments(){
return threadLocal.get();
}
public static void clear(){
threadLocal.remove();
}
public static String getShopId(){
return String.valueOf(threadLocal.get().get("shopId"));
}
}
设置参数的方法
Map<String,Object> map=new HashMap<String,Object>();
map.put("shopId","test");
TenantContext.addAttachments(map);
实际应用 设置参数
@Slf4j
public class WebHandlerInterceptor implements HandlerInterceptor {
/**
* 请求方法执行之前
* 返回true则通过
* @param request
* @param response
* @param handler
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String authorization = request.getHeader("Authorization");
if (!StringUtils.isEmpty(authorization)) {
try {
Map<String,Object> tokenMap = JWTUtil.decode(authorization);
TenantContext.addAttachments(tokenMap);
} catch (Exception ex) {
log.error("解析token出错");
// return false;
}
}
return true;
}
}
获取参数
@Bean
public PaginationInterceptor paginationInterceptor() {
System.out.println("paginationInterceptor---");
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// SQL解析处理拦截:增加租户处理回调。
TenantSqlParser tenantSqlParser = new TenantSqlParser()
.setTenantHandler(new TenantHandler() {
@Override
public Expression getTenantId(boolean where) {
// 暂时写死,用于测试
// String shopId = "test";
//从RPCContext对象中获取shopid
String shopId = RpcContext.getContext().getAttachment("shopId");
if (null == shopId) {
throw new RuntimeException("#1129 getCurrentProviderId error.");
}
return new StringValue(shopId);
}
@Override
public String getTenantIdColumn() {
return SYSTEM_TENANT_ID;
}
@Override
public boolean doTableFilter(String tableName) {
// 忽略掉一些表:如租户表(provider)本身不需要执行这样的处理。
return IGNORE_TENANT_TABLES.stream().anyMatch((e) -> e.equalsIgnoreCase(tableName));
}
});
paginationInterceptor.setSqlParserList( Lists.newArrayList(tenantSqlParser));
return paginationInterceptor;
}