Micrometer 系列【54】统一观测:Context | 上下文容器
文章目录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);}}

相关新闻

Chateau框架API完全参考:轻松掌握聊天功能开发接口

Chateau框架API完全参考:轻松掌握聊天功能开发接口

Chateau框架API完全参考:轻松掌握聊天功能开发接口 【免费下载链接】Chateau Chateau is a framework for adding (or improving) chat functionality in any Android app 项目地址: https://gitcode.com/gh_mirrors/cha/Chateau Chateau是一款专为Android应…

2026/10/15 15:07:58 阅读更多 →
物流行业跨境报关自动化怎么做?企业级AI Agent落地架构与主流方案解析

物流行业跨境报关自动化怎么做?企业级AI Agent落地架构与主流方案解析

在当前全球贸易环境日益复杂的背景下,跨境物流企业正面临着报关链路长、HS Code归类难、单证非结构化数据多以及合规风控压力大等核心痛点。传统的“经验排柜Excel对账”模式已无法满足现代跨境电商及B2B贸易的高效履约需求。随着大模型落地与企业智能自动化技术的演…

2026/10/15 15:08:02 阅读更多 →
Golongpoll与Gin框架集成:构建高性能实时Web应用

Golongpoll与Gin框架集成:构建高性能实时Web应用

Golongpoll与Gin框架集成:构建高性能实时Web应用 【免费下载链接】golongpoll golang long polling library. Makes web pub-sub easy via HTTP long-poll servers and clients :smiley: :coffee: :computer: 项目地址: https://gitcode.com/gh_mirrors/go/golong…

2026/10/15 15:31:22 阅读更多 →

最新新闻

木门产品知识全解析:从分类、材质到测量安装避坑指南

木门产品知识全解析:从分类、材质到测量安装避坑指南

简介:这是一份面向木门行业从业者(销售、门店人员、安装技工)的产品知识培训资料,以单份doc文档收录,共1个文件,压缩包约3.28MB。内容从门的文化内涵、历史演变切入,系统梳理门按材质、开启方式…

2026/10/20 2:02:14 阅读更多 →
AGI时代开发者指南:大模型应用、RAG与Agent工程实践

AGI时代开发者指南:大模型应用、RAG与Agent工程实践

如果只看表面的技术动态,AGI时代给人的感觉是“模型又变强了”;但站在开发者角度,我更愿意把它理解为一次开发范式的变化:以前我们通过编写规则让软件工作,现在越来越多的工作变成了通过提示词、检索、工具调用和智能体…

2026/10/20 2:02:14 阅读更多 →
把AO接回来:黑线与白底之间差了多少空间关系

把AO接回来:黑线与白底之间差了多少空间关系

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 2:02:14 阅读更多 →
ISO质量认证体系文件落地指南:从PDF到可执行框架与内审闭环

ISO质量认证体系文件落地指南:从PDF到可执行框架与内审闭环

简介:这份PDF资料围绕ISO质量认证体系展开,面向企业质量管理人员、体系推行专员及备考质量管理相关认证的学习者,帮助读者系统理解质量体系认证的起源、标准框架与落地要点。内容从1903年英国“BS”风筝标志讲起,梳理质量认证从产…

2026/10/20 2:02:14 阅读更多 →
OpenCV人脸识别实战:从环境配置到LBPH阈值调优

OpenCV人脸识别实战:从环境配置到LBPH阈值调优

简介:这份资源面向具备Python基础、希望入门机器视觉与人脸识别的开发者与学习者,以OpenCV为核心工具,围绕明星人脸检测与识别这一具体场景展开实战。压缩包共120个文件,以110张jpg与5张jpeg人脸样本图片为主体,另含2个…

2026/10/20 2:02:14 阅读更多 →
EfficientNetV2架构深度解析:tf_efficientnetv2_b3.in1k为何能又快又小?

EfficientNetV2架构深度解析:tf_efficientnetv2_b3.in1k为何能又快又小?

【免费下载链接】tf_efficientnetv2_b3.in1k 项目地址: https://ai.gitcode.com/hf_mirrors/timm/tf_efficientnetv2_b3.in1k 点击查看 免费下载 本文以开源预训练模型 tf_efficientnetv2_b3.in1k 为例,带你快速看懂这个图像分类模型:它仅用…

2026/10/20 2:01:14 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →