文章目录1. 概述1.1 基础定义1.2 核心特征1.3 工作原理1创建阶段2启动观测3执行业务逻辑4观测结束2. 源码分析2.1 ContextView只读视图接口2.2 Context可变实现类2.3 ClientRequestObservationContext 上层扩展3. 完整示例3.1 自定义上下文容器3.2 自定义观测处理器3.3 业务服务类3.4 程序入口1. 概述1.1 基础定义一次观测生命周期内统一存放本次事件所有元数据、业务对象、标签、异常、链路信息的数据载体。一次WebClient请求 /HTTP Server请求 / 方法调用就是一次Observation整个事件从开始到结束需要一个数据载体里面装着Request、Response、URL模板、异常、自定义标签、父链路信息、自定义业务对象这个存放数据的容器就是就是上下文容器。在Micrometer Observation体系中只读对外视图ContextView可变实现Context业务扩展ClientRequestObservationContext、ServerRequestObservationContext等继承扩展1.2 核心特征生命周期绑定Observation容器随Observation创建而生观测结束后不再使用单一事件私有每个Observation拥有独立Context不会和其他请求互相污染读写分离模型业务代码持有可变Context写入数据所有处理器Metrics、Tracing Handler只能拿到只读ContextView只允许读取承载两类数据① 通用业务对象MapObject,ObjectRequest、Response、DTO② 可观测标签Low/High Cardinality KeyValue用于指标、Trace Span属性1.3 工作原理1创建阶段开发者提前组装上下文填充本次事件所有信息Observation内部持有上下文引用// 创建业务扩展上下文容器ClientRequestObservationContextcontextnewClientRequestObservationContext(request);context.setUriTemplate(/order/{id});context.addLowCardinalityKeyValue(...);// 绑定到 ObservationObservationobservationObservation.createNotStarted(http.client.requests,()-context,registry);2启动观测触发所有注册的ObservationHandler#onStart(ContextView)处理器从Context中获取数据进行相关处理。比如链路追踪TracingHandler可以读取parentObservation获取父Span信息创建子Span读取contextView.getContextualName()/getName()设置Span名称读取高低基数KeyValues作为Span初始Attributes创建Trace Scope把TraceContext (traceId/spanId)设置到当前线程传给Handler的是ContextView只读视图禁止处理器修改容器数据。3执行业务逻辑业务代码可以继续操作原始可变Context设置异常context.setError(throwable)追加标签、存入返回对象response4观测结束observation.stop()触发依次执行Handler的onStop(ContextView)Micrometer Metrics Handler读取低基数标签生成Prometheus指标Timer/CounterTracing Handler如Brave/Otel读取全部标签构建Span写入链路追踪观测完成后上下文不再被框架使用异步场景需要开发者注意不要继续复用。2. 源码分析整体分层关系ContextView只读视图←Context可变实现← 业务扩展类ClientRequestObservationContext2.1 ContextView只读视图接口设计意图读写分离对外传给ObservationHandler、ObservationConvention的统一类型是ContextView只能读不能修改上下文。只有创建Observation的业务代码持有可变Context实例防止Handler随意篡改观测上下文。interfaceContextViewObservation基础标识字段方法作用getName()Observation 固定名称如http.client.requests指标名主体getContextualName()运行时动态名称例如 HTTP 方法路径用于 span namegetParentObservation()父 Observation构建链路追踪父子关系getError()本次观测发生的异常用于标记 span error、指标异常标签通用业务容器KV Map字段ConcurrentHashMapObject,Object map自定义业务数据仓库存放业务自定义对象getRequired不存在直接抛IllegalArgumentException适合强依赖场景。TTget(Objectkey);TTgetRequired(Objectkey);booleancontainsKey(Objectkey);TTgetOrDefault(...)Micrometer强制区分低基数 Low Cardinality / 高基数 High Cardinality方法清单KeyValuesgetLowCardinalityKeyValues();KeyValuesgetHighCardinalityKeyValues();KeyValuegetLowCardinalityKeyValue(Stringkey);KeyValuegetHighCardinalityKeyValue(Stringkey);KeyValuesgetAllKeyValues();规则ObservationConvention会生成一批标准标签通过addLowCardinalityKeyValue()添加的标签追加到Convention生成标签集合Handler在处理metrics/tracing时会分别读取两类标签做不同处理。2.2 Context可变实现类SuppressWarnings(unchecked)classContextimplementsContextView内部存储结构// 通用业务对象存储privatefinalMapObject,ObjectmapnewConcurrentHashMap();// 低基数标签privatefinalMapString,KeyValuelowCardinalityKeyValuesnewConcurrentHashMap();// 高基数标签privatefinalMapString,KeyValuehighCardinalityKeyValuesnewConcurrentHashMap();// 基础元数据privateStringname;privateStringcontextualName;privateThrowableerror;privateObservationViewparentObservation;全部使用ConcurrentHashMap→Observation可能跨线程使用线程安全设计。新增可变操作ContextView没有元数据settersetName / setContextualName / setParentObservation / setError业务map操作put / remove / computeIfAbsent / clear标签操作addLowCardinalityKeyValue / removeLowCardinalityKeyValue批量操作setParentFromCurrentObservation()自动从registry.getCurrentObservation()获取当前线程活跃Observation作为父节点自动构建链路上下文。2.3 ClientRequestObservationContext 上层扩展上次模块Maven: org.springframework:spring-web:6.2.16RequestReplySenderContext是Spring基于Micrometer Context封装的通用客户端请求-应答上下文模板内置request/response对象持有支持传播tracing载体Propagation carrier注入HTTP Headertraceparent等publicclassClientRequestObservationContextextendsRequestReplySenderContextClientHttpRequest,ClientHttpResponse3. 完整示例场景单进程内部调用创建订单(根Observation) → 发起支付(子Observation)核心演示自定义业务Observation.Context上下文容器观测自动父子关系构建onStart/onStop生命周期、ContextView只读约束Low/High Cardinality标签区分不依赖任何Spring仅micrometer原生API3.1 自定义上下文容器自定义订单业务上下文容器继承Observation.Context可变上下文。业务代码可写入字段、高低基数标签、自定义对象作为一次订单观测的数据包供后续Handler读取。publicclassOrderObservationContextextendsObservation.Context{privateStringorderNo;privateLonguserId;privateStringorderType;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNoorderNo;// 高基数唯一流水号仅用于Trace禁止指标Tag防止时序爆炸addHighCardinalityKeyValue(KeyValue.of(order.no,orderNo));}publicLonggetUserId(){returnuserId;}publicvoidsetUserId(LonguserId){this.userIduserId;addHighCardinalityKeyValue(KeyValue.of(user.id,String.valueOf(userId)));}publicStringgetOrderType(){returnorderType;}publicvoidsetOrderType(StringorderType){this.orderTypeorderType;// 低基数枚举维度Metrics指标 Trace链路都可以使用addLowCardinalityKeyValue(KeyValue.of(order.type,orderType));}}支付业务专属上下文容器独立上下文每一次支付观测创建独立实例隔离数据。publicclassPaymentObservationContextextendsObservation.Context{privateStringorderNo;privateStringpayChannel;publicStringgetOrderNo(){returnorderNo;}publicvoidsetOrderNo(StringorderNo){this.orderNoorderNo;addHighCardinalityKeyValue(KeyValue.of(pay.order.no,orderNo));}publicStringgetPayChannel(){returnpayChannel;}publicvoidsetPayChannel(StringpayChannel){this.payChannelpayChannel;addLowCardinalityKeyValue(KeyValue.of(pay.channel,payChannel));}}3.2 自定义观测处理器所有Handler入参为ContextView只读视图禁止修改上下文容器。监听观测生命周期onStart观测启动、onStop观测结束打印上下文信息演示数据消费逻辑。/** * 自定义日志处理器消费只读上下文 ContextView */publicclassBizLogObservationHandlerimplementsObservationHandlerObservation.ContextView{/** * 观测启动回调业务逻辑还未执行拿不到响应/异常 */OverridepublicvoidonStart(Observation.ContextViewcontextView){System.out.println(\n onStart );System.out.println(观测名称contextView.getName());System.out.println(父观测contextView.getParentObservation());if(contextViewinstanceofOrderObservationContextctx){System.out.println([订单上下文] orderNoctx.getOrderNo(), typectx.getOrderType());System.out.println(自定义扩展数据ctx.get(ext.info));}if(contextViewinstanceofPaymentObservationContextctx){System.out.println([支付上下文] orderNoctx.getOrderNo(), channelctx.getPayChannel());}System.out.println(低基数标签集合contextView.getLowCardinalityKeyValues());System.out.println(\n);}/** * 观测结束回调业务执行完成可以读取异常、耗时相关信息 */OverridepublicvoidonStop(Observation.ContextViewcontextView){System.out.println(\n onStop );System.out.println(观测名称contextView.getName());ThrowableerrorcontextView.getError();if(error!null){System.out.println(观测异常error.getMessage());}System.out.println(\n);}/** * 匹配器只处理我们自定义的业务上下文过滤系统内置上下文 */OverridepublicbooleansupportsContext(Observation.ContextViewcontext){returncontextinstanceofOrderObservationContext||contextinstanceofPaymentObservationContext;}}3.3 业务服务类支付业务服务创建子Observation启动时自动寻找当前线程活跃观测自动构建父子链路。/** * 支付服务生成子观测 payment.create */publicclassPaymentService{privatefinalObservationRegistryregistry;publicPaymentService(ObservationRegistryregistry){this.registryregistry;}publicvoidpay(StringorderNo){// 创建支付专属上下文容器PaymentObservationContextpayContextnewPaymentObservationContext();payContext.setOrderNo(orderNo);payContext.setPayChannel(WECHAT);// 创建未启动观测绑定上下文容器ObservationpayObservationObservation.createNotStarted(payment.create,()-payContext,registry);// observe() 封装模板start() → 执行业务 → stop()payObservation.observe(()-{System.out.println(执行业务发起支付 orderNoorderNo);sleep(120);});}privatevoidsleep(longms){try{Thread.sleep(ms);}catch(InterruptedExceptione){thrownewRuntimeException(e);}}}订单业务服务创建根Observation内部调用PaymentService形成调用链路。业务发生异常时把异常写入上下文容器供Handler捕获。/** * 订单服务生成根观测 order.create */publicclassOrderService{privatefinalObservationRegistryregistry;privatefinalPaymentServicepaymentService;publicOrderService(ObservationRegistryregistry,PaymentServicepaymentService){this.registryregistry;this.paymentServicepaymentService;}publicvoidcreateOrder(StringorderNo,LonguserId,StringorderType){// 初始化订单上下文容器填充业务数据OrderObservationContextorderContextnewOrderObservationContext();orderContext.setOrderNo(orderNo);orderContext.setUserId(userId);orderContext.setOrderType(orderType);// put方式存放自定义对象不会自动成为标签需要手动读取orderContext.put(ext.info,订单附加备注信息);ObservationorderObservationObservation.createNotStarted(order.create,()-orderContext,registry);orderObservation.observe(()-{try{System.out.println(执行业务创建订单 orderNoorderNo);sleep(100);// 内部调用支付子观测自动关联父观测paymentService.pay(orderNo);}catch(Exceptione){// 将异常存入上下文容器onStop阶段处理器读取orderContext.setError(e);throwe;}});}privatevoidsleep(longms){try{Thread.sleep(ms);}catch(InterruptedExceptione){thrownewRuntimeException(e);}}}3.4 程序入口创建ObservationRegistry观测注册中心注册自定义Handler组装并执行业务流程。publicclassObservationMain{publicstaticvoidmain(String[]args){// 1. 创建观测注册中心ObservationRegistryregistryObservationRegistry.create();// 2. 注册自定义观测处理器registry.observationConfig().observationHandler(newBizLogObservationHandler());// 3. 初始化业务 BeanPaymentServicepaymentServicenewPaymentService(registry);OrderServiceorderServicenewOrderService(registry,paymentService);// 4. 执行完整业务流程orderService.createOrder(OD20260813_001,10001L,NORMAL);}}