作者回复: 你好,张三丰:你站在的角度是消费者应用一定是请求的源头,所以你会这么理解。若消费方是前端呢?难道需要前端来生成traceId么? 只是站在看问题的角度不同罢了,不过也挺好的,说明至少是认真在思考这个traceId传递衔接的问题,挺棒的。 我这里引用我之前回答过的内容,如下: 说消费方还有点不太准确,精准点说,应该是从接收请求的那个源头就可以考虑生成traceId。 比如接收前端请求,Web容器比如Tomcat的Filter是最能第一时间感知请求的存在,可以在这里进行拦截直接生成TraceId,至于Tomcat在Filter之后的一些处理环节,就可以直接拿到TraceId了。再进入Controller调用下游Dubbo接口的话,消费方发现上下文没有 traceId 的也是可以考虑生成,也是一种兼容考虑方法,挺好的。 比如 A ->B -> C,抛开Web容器来看待的话,A 的消费方过滤器其实拿到的 traceId 是 null 值,但是 B 所能很好衔接 traceId 的话,那么 B 在发起调用 C 的时候,B 的消费方过滤器是能正常拿到 traceId 的。
作者回复: 你好,Lum:你刚刚所描述的场景,其实就是【任务一】虚线框中的场景,这种是比较单一的,对于单一的场景,大可以拿着一堆的 Future 列表挨个调用 get 方法,但是如果 Future 与 Future 之间如果有先后顺序、结果聚合、逻辑计算等等,那一直使用 get 操作就玩不转了~
作者回复: 你好,小白:org.apache.dubbo.rpc.RpcContext#get()、org.apache.dubbo.rpc.RpcContext#set、org.apache.dubbo.rpc.RpcContext#remove、org.apache.dubbo.rpc.RpcContext#get(java.lang.String) 等等 API 已经在 RpcContext 中被标注 @Deprecated 注解,说明在新版本是不再建议使用了。 而是使用更加明确的获取方式(invocation.getObjectAttachments()、RpcContext.getClientAttachment()),从 invocation 中获取数据是明确表示该数据一定是从接收的参数中获取的,这是一种见名知意的写代码表述方式而已。 但是这里你还要结合 ContextFilter、ConsumerContextFilter 来看,你要把数据放对就行了。
作者回复: 你好,高级按摩师:了解下 ThreadLocal 这个东西,就是靠它来进行衔接的。
作者回复: 你好,乌凌先森:这俩注解各自解决的问题不一样: 1.@DubboService 解决的是在编码层面时接口实现类可以处理Dubbo的接收请求。 2.@Component 解决的是在 Spring 框架中该接口实现类变成单实例对象以便后续可以被 @Autowired、@Resource 进行注入使用。
作者回复: 你好,Geek_10086:说消费方还有点不太准确,精准点说,应该是从接收请求的那个源头就可以考虑生成traceId。 比如接收前端请求,Web容器比如Tomcat的Filter是最能第一时间感知请求的存在,可以在这里进行拦截直接生成TraceId,至于Tomcat在Filter之后的一些处理环节,就可以直接拿到TraceId了。再进入Controller调用下游Dubbo接口的话,消费方发现上下文没有 traceId 的也是可以考虑生成,也是一种兼容考虑方法,挺好的。 至于你说的消费方过滤器默认为 null 的情况,一半对一半不对,比如 A ->B -> C,抛开Web容器来看待的话,A 的消费方过滤器其实拿到的 traceId 是 null 值,但是 B 所能很好衔接 traceId 的话,那么 B 在发起调用 C 的时候,B 的消费方过滤器是能正常拿到 traceId 的。
作者回复: 你好,王巍:你问得这个细节非常 nice,进程中多线程的 traceId 传递,是另外一个话题。 这里我给个大概思路,你可以单独将这些多线程之间如何传递 traceId 做成一个插件,比如可以横切Spring的AsyncTaskExecutor的方法,比如统一指定公司规范使用某几种 Runnable/Callable 来操作线程,比如 MQ/Job 在触发时刻的源头直接自动横切一刀赋上traceId,等等等等,总之旨在将方法执行前与方法执行后的traceId衔接起来。