dubbo中如何传递隐式参数?
像traceid如何传参问题?
1 个回答
不必太张扬,是花自然香。ketty### Dubbo 中如何传递隐式参数? 在 Dubbo 服务调用中,使用 `ThreadLocal` 是无法进行跨线程的对象传递的,即使使用 `InheritableThreadLocal` 也无法实现父子线程的传递。这种情况下,可以使用 Dubbo 的 `RpcContext` 来进行参数的隐式传递。 ### 使用 RpcContext 进行参数隐式传递 #### 1. 设置隐式参数 在服务调用前,通过 `RpcContext` 设置隐式参数。以下是一个示例代码: ```java @Component @Slf4j public class TokenHandler implements HandlerInterceptor { @Reference private ZcLoginService zcLoginService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { String token = httpServletRequest.getHeader("tokenId"); log.info("请求 token: {}", token); if (StringUtils.isEmpty(token)) { throw new TokenException("用户 token 不存在,请重新登录"); } // 校验 token 的真实性 ResponseData<Customer> responseData = zcLoginService.findToken(token); log.info("解析后的 token:{}", JSON.toJSONString(responseData)); if (!ExceptionEnum.SUCCESS.getCode().equals(responseData.getCode())) { throw new TokenException(responseData.getCode(), responseData.getMessage()); } // 设置隐式参数 Map<String, String> map = new HashMap<>(); map.put("userKey", "userValue"); RpcContext.getContext().setAttachments(map); return true; } } ``` #### 2. 获取隐式参数 在服务的实现类中,通过 `RpcContext` 获取隐式参数。 ```java @Override public IdentifyRiskBookRsp queryIdentifyRiskBookByFlowId(IdentifyReq record) { System.out.println("RpcContext.getContext().get(userKey): " + RpcContext.getContext().getAttachments()); // 业务逻辑 } ``` ### 隐式参数传递的实现机制 在 Dubbo 的 Protocol 层,每次消费者调用过程中,会依次调用 `ConsumerContextFilter` 的 `invoke` 方法、`FutureFilter` 的 `invoke` 方法和 `MonitorFilter` 的 `invoke` 方法,最后会调用 `DubboInvoker` 的 `invoke` 方法。 以下是 `ConsumerContextFilter` 的 `invoke` 方法的实现: ```java @Activate(group = Constants.CONSUMER, order = -10000) public class ConsumerContextFilter implements Filter { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { RpcContext.getContext() .setInvoker(invoker) .setInvocation(invocation) .setLocalAddress(NetUtils.getLocalHost(), 0) .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()); if (invocation instanceof RpcInvocation) { ((RpcInvocation) invocation).setInvoker(invoker); } try { return invoker.invoke(invocation); } finally { RpcContext.getContext().clearAttachments(); } } } ``` 每次 Dubbo 接口调用结束后,`RpcContext` 的 `attachments` 会被清除。如果服务调用链是 A -> B -> C,那么在 B 服务中取出参数后,到 C 服务时就无法获取参数。因此,需要在每个服务中重新设置隐式参数。 ### 总结 通过以上方法,使用 `RpcContext` 可以在 Dubbo 服务调用链中传递隐式参数。但需要注意的是,每次服务调用结束后,`RpcContext` 的 `attachments` 会被清除,如果服务调用链较长,需要在每个服务中重新设置隐式参数,以确保参数能够在整个调用链中传递。编辑于 2024-04-17 02:46 •IP属地 北京举报评论收藏
公众号进入网站体验更佳

