拓冰建站拓冰建站
首页 / 资讯中心 / 正文

CAT 切面注解埋点实战:SpringMVC 环境下基于 AOP 的零侵入监控方案

可观测性指标监控告警APM后端链路追踪【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址https://gitcode.com/gh_mirrors/ca/cat点击查看免费下载本指南围绕 CAT 项目提供的springMVC-AOP集成方案展开讲解如何以切面注解方式快速对系统进行埋点只需在需要监控的类或方法上添加注解即可自动生成 CAT Transaction 上报同时配合 Filter 完成 URL 请求级埋点与动态 URL 聚合。读完本文你将掌握CatTransaction、CatCacheTransaction、CatHttpRequestTransaction、CatDubboClientTransaction四类注解的完整用法、底层切面实现原理以及配套的 MyBatis SQL 埋点与切面装配方式可直接落地到基于 Spring/SpringMVC 的业务项目中。一、方案概述为什么用切面注解埋点CAT大众点评开源的应用监控平台要求业务代码通过Cat.newTransaction/Cat.logEvent等 API 主动上报数据。如果每个方法都手写「开启 Transaction → 执行业务 → 设置状态 → complete」会带来大量重复样板代码且容易在异常分支遗漏状态设置。springMVC-AOP集成方案的做法是把「开启、收尾、记录状态」的共性逻辑统一收敛进切面CatAspect.java业务侧只负责在方法上加一个注解由 AspectJ 在运行时拦截并完成埋点。该方案在仓库的 integration/README.md 中被归入「埋点方案」体系与 log4j2、logback、spring-boot、mybatis 等集成并列。需要明确的是注解方式会引入 AOP 代理与反射开销原文档也明确提示会有性能影响因此适用于对响应时间不敏感的内部方法如缓存读写、Dubbo 客户端调用、URL 聚合而不是每一条高频热点路径。二、前置准备引入依赖并配置 CatFilter1. 添加 cat-client 依赖在pom.xml中引入 CAT 客户端dependency groupIdcom.dianping.cat/groupId artifactIdcat-client/artifactId version2.0.0/version /dependency版本号以你实际接入的 CAT 服务端版本为准这里仅为原文档示例CAT部署.txt。2. 在 web.xml 中配置 CatFilter原文档给出的第一步是在web.xml中添加 Filterurl-pattern配置为需要埋点的 restful 接口其目的是让请求级埋点只作用于业务接口、防止静态资源乱入filter filter-namecat-filter/filter-name filter-classcom.dianping.cat.servlet.CatFilter/filter-class /filter filter-mapping filter-namecat-filter/filter-name url-pattern/test1//url-pattern url-pattern/test2//url-pattern dispatcherREQUEST/dispatcher dispatcherFORWARD/dispatcher /filter-mapping要点说明url-pattern按需写业务接口前缀如/api/、/orders/避免/*全量匹配导致图片、CSS、JS 等静态资源也进入埋点链路。dispatcher同时配置REQUEST与FORWARD保证直接请求与转发后的请求都能被拦截上报。从当前仓库源码看Filter 的实际实现类位于 cat-client/src/main/java/com/dianping/cat/support/servlet/CatFilter.java它承担了 URL 请求级埋点的大部分工作——即原文档所说「该 filter 已经对 URL 请求做了大部分的埋点工作」。若你的 cat-client 版本类路径不同请以实际 jar 内类名为准。3. 客户端全局配置Filter 与切面最终都依赖 cat-client 上报链路因此还需保证客户端配置就绪在src/main/resources/META-INF/下新建app.properties写入app.name你的应用名并把client.xml含 CAT 服务端ip/port列表放置到/data/appdatas/cat/目录下详见 CAT部署.txt 中的客户端配置章节。三、通用方法埋点注解 CatTransaction在切面注解体系中CatTransaction是最基础的一枚注解适用于任意需要以 Transaction 维度统计的方法。注解定义CatTransaction.java 定义了两个属性Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface CatTransaction { String type() default Handler; // URL MVC Service SQL is reserved for Cat Transaction Type String name() default ; }typeTransaction 类型默认Handler。源码注释特别提醒URL、MVC、Service、SQL是 CAT 预留的 Transaction 类型自定义时不要占用这些保留字以免与 CAT 自身埋点类型冲突。nameTransaction 名称为空时由切面根据方法签名自动生成。切面实现原理对应切面方法为catTransactionProcessCatAspect.javaAround(annotation(catTransaction)) public Object catTransactionProcess(ProceedingJoinPoint pjp, CatTransaction catTransaction) throws Throwable { String transName pjp.getSignature().getDeclaringType().getSimpleName() . pjp.getSignature().getName(); if (StringUtils.isNotBlank(catTransaction.name())) { transName catTransaction.name(); } Transaction t Cat.newTransaction(catTransaction.type(), transName); try { Object result pjp.proceed(); t.setStatus(Transaction.SUCCESS); return result; } catch (Throwable e) { t.setStatus(e); throw e; } finally { t.complete(); } }关键设计点默认命名规则不写name时Transaction 名为简单类名.方法名如OrderService.getOrders天然具备可读性显式指定name则覆盖默认值适合做跨方法聚合。异常语义方法抛异常时调用t.setStatus(e)记录异常信息并重新抛出不吞异常、不改变业务行为正常路径设置SUCCESS。finally 兜底无论成功失败都在finally中complete()保证 Transaction 一定被闭合、不会泄漏。使用示例CatTransaction // 默认 typeHandlername简单类名.方法名 public void processOrder(Long orderId) { // 业务逻辑 } CatTransaction(type Service, name OrderCreate) public void createOrder(Order order) { // 业务逻辑 }四、缓存埋点注解 CatCacheTransaction针对缓存读写场景典型如 Redis 封装CatCacheTransaction把每次缓存操作封装成一个Cache.Redis类型的事务并额外上报缓存服务器事件。注解定义CatCacheTransaction.javaRetention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface CatCacheTransaction { String name() default ; String server() default Default; }name事务名默认取被拦截方法名如get、put、delete。server缓存服务器标识默认Default用于区分不同缓存实例。切面实现与上报结构对应切面方法catCacheTransactionProcessTransaction t Cat.newTransaction(Cache.Redis, transName); try { Cat.logEvent(Cache.Server, catCacheTransaction.server()); Object result pjp.proceed(); t.setStatus(Transaction.SUCCESS); return result; } catch (Throwable e) { Cat.logEvent(Cache.Server, catCacheTransaction.server(), -1, null); t.setStatus(e); throw e; } finally { t.complete(); }上报的数据结构为上报项类型值TransactiontypeCache.Redisname方法名或注解 nameEventtypeCache.Server成功时值为server()属性失败时值为server() 状态码-1成功/失败两条分支都会记录Cache.Server事件但失败分支额外携带状态码-1便于在 CAT 报表中按「缓存服务器 是否失败」快速筛选定位。使用示例原文档示例CatCacheTransaction public V get(K key) { // 缓存读取 } CatCacheTransaction public void put(K key, V value) { // 缓存写入 } CatCacheTransaction public void delete(K key) { // 缓存删除 } // 显式指定缓存服务器 CatCacheTransaction(name OrderCache.get, server redis-order-01) public Order getOrder(Long orderId) { // ... }五、URL 聚合注解 CatHttpRequestTransaction背景为什么要做 URL 聚合SpringMVC 中带路径参数的接口如/orders/{userId}/{orderStatus}如果按原始 URL 埋点每个用户 ID、订单状态组合都会生成独立的事务名导致 CAT 报表出现海量 URL 分散项既浪费服务端存储、又难以看清接口整体趋势。切面方案通过After在响应前改写请求属性cat-page-uri把动态 URL 归一到固定业务名从而降低 CAT 服务压力原文档原话。注解定义CatHttpRequestTransaction定义如下与 CatAspect.java 配套原文档在 CAT部署.txt 中给出了完整定义Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface CatHttpRequestTransaction { String name() default ; String type() default URL; }切面实现对应切面方法catHttpRequestProcess是After通知不做事务包裹只改写请求属性After(annotation(catHttpRequestTransaction)) public void catHttpRequestProcess(CatHttpRequestTransaction catHttpRequestTransaction) { HttpServletRequest request ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); if (StringUtils.isNotBlank(catHttpRequestTransaction.name())) { String transName catHttpRequestTransaction.name(); request.setAttribute(cat-page-uri, transName); } }工作原理Filter 端读取cat-page-uri请求属性作为 URL 事务名切面在 Controller 方法返回后After不影响方法返回值把注解上的聚合名写入该属性。因此注解的name必须与 Filter 的 url-pattern 命中范围配合使用才能对同前缀的接口做归并。使用示例原文档示例RequestMapping(value /orders/{userId}/{orderStatus}) ResponseBody CatHttpRequestTransaction(type URL, name /orders) public String userOrders() { // 无论 userId/orderStatus 如何变化CAT 报表中 URL 统一显示为 /orders }实践中type使用默认值URL即可需要区分来源时也可自定义原文档给出的注解type()默认即为URL。注意只有name非空时切面才会改写cat-page-uri留空则保持 Filter 的默认行为。六、Dubbo 客户端调用埋点注解 CatDubboClientTransaction对发起 Dubbo 调用的客户端方法CatDubboClientTransaction会生成Call类型事务并以事件形式记录被调应用与服务用于跨服务调用链分析。注解定义CatDubboClientTransaction.javaRetention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface CatDubboClientTransaction { String name() default ; String callServer(); String callApp(); }注意与前面注解的差异callServer()与callApp()是必填属性无 default编译期强制要求填写被调服务与被调应用。切面实现与上报结构对应切面方法Transaction t Cat.newTransaction(Call, transName); try { Cat.logEvent(Call.app, catDubboClientTransaction.callApp()); Cat.logEvent(Call.server, catDubboClientTransaction.callServer()); Object result pjp.proceed(); t.setStatus(Transaction.SUCCESS); return result; } catch (Throwable e) { t.setStatus(e); throw e; } finally { t.complete(); }上报的数据结构为上报项类型值TransactiontypeCallname方法名或注解 nameEventtypeCall.appcallApp()被调应用EventtypeCall.servercallServer()被调服务这三个维度组合后可在 CAT 中分析「本应用 → 某应用 → 某服务」的调用量、耗时与错误率。使用示例原文档示例CatDubboClientTransaction(callApp orders, callServer orderServer) public ListLong getOrdersByUser() { // 内部发起 Dubbo 调用 }七、配套 SQL 埋点CatMybatisInterceptor切面注解体系之外springMVC-AOP目录还附带了一份 MyBatis SQL 埋点的完整实现 CatMybatisInterceptor.java用于补全「SQL」这一 CAT 预留事务类型。拦截器实现要点该拦截器通过 MyBatisIntercepts注解拦截Executor的update与query两个方法Intercepts({ Signature(type Executor.class, method update, args { MappedStatement.class, Object.class }), Signature(type Executor.class, method query, args { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class CatMybatisInterceptor implements Interceptor {核心逻辑与切面如出一辙以MappedStatement.getId()即 Mapper 方法的全限定名作为事务名创建CatConstants.TYPE_SQL类型事务同时上报SQL.Database数据源 URL通过 properties 注入与SQL.Methodupdate/query两个事件异常时Cat.logError(e)记录堆栈。此外还提供了showSql工具方法可将BoundSql中的?占位符替换为真实参数值便于生成可执行 SQL 日志。接入方式原文档示例在mybatis-config.xml中注册插件并通过 property 传入数据源 URL!--mybatis cat interceptor -- plugin interceptorcom.test.center.util.aspect.CatMybatisInterceptor property namedatasourceUrl value${center.jdbc.url}/ /plugin八、切面装配让注解生效注解本身不产生任何拦截必须把CatAspect注册为 Spring 管理的 Aspect 才能生效。仓库以纯 Java 类提供切面CatAspect标注了Aspect但未标注Component实际项目中可用以下任一方式装配方式一Spring XML 配置bean idcatAspect classcom.yourcompany.aop.CatAspect/ aop:aspectj-autoproxy/方式二Spring Boot / Java ConfigConfiguration EnableAspectJAutoProxy public class CatAopConfig { Bean public CatAspect catAspect() { return new CatAspect(); } }两点实践提醒切面生效依赖 Spring AOP 代理因此不能直接监控同类内部方法调用this.method()形式绕过代理跨 Bean 调用才能被拦截。若项目同时使用CatAopService这类通用切面参考 integration/spring-aop/cat-aop/CatAopService.java其Around(annotation(CatAnnotation))会把任意标注CatAnnotation的方法包装成method类型事务注意与本文注解的拦截规则相互独立、互不影响可按需选用其一或并存。九、性能影响与使用建议原文档明确提示注解方式「会有性能影响」结合前文源码分析给出如下使用建议注解粒度控制优先在方法入口、跨组件调用边界缓存、RPC、SQL埋点避免在超高频循环体内层方法上加注解。善用 name 聚合URL、Dubbo 调用场景务必设置合理的name/callApp/callServer聚合维度否则动态参数会造成事务名爆炸反而加重 CAT 服务端压力——这正是CatHttpRequestTransaction存在的意义。保留字规避自定义type时不要使用URL、MVC、Service、SQL等 CAT 预留类型见 CatTransaction.java 注释。与 Filter 分工明确Filter 负责请求级 URL 埋点配置在 web.xml注解负责方法级/跨服务埋点两者配合形成「请求 → 方法 → 缓存/DB/Dubbo」的多层监控视图。十、小结springMVC-AOP集成方案把 CAT 埋点从「手写 API 调用」升级为「声明式注解」本文四枚注解的职责可归纳如下注解适用场景Transaction 类型关键属性CatTransaction任意业务方法自定义默认Handlertype、nameCatCacheTransaction缓存读写Cache.Redisname、serverCatHttpRequestTransactionURL 聚合配合 Filter 改写cat-page-uriname默认typeURLCatDubboClientTransactionDubbo 客户端调用CallcallApp、callServer必填配合CatMybatisInterceptor的 SQL 埋点即可在 SpringMVC 项目中快速构建「URL / 方法 / Cache / SQL / Dubbo」全链路监控。相关可复用的切面与注解源码均位于 integration/springMVC-AOP 目录部署与客户端配置细节可进一步参考 CAT部署.txt。赞分享可观测性指标监控告警APM后端链路追踪【免费下载链接】catCAT 作为服务端项目基础组件提供了 Java, C/C, Node.js, Python, Go 等多语言客户端已经在美团点评的基础架构中间件框架MVC框架RPC框架数据库框架缓存框架等消息队列配置系统等深度集成为美团点评各业务线提供系统丰富的性能指标、健康状况、实时告警等。项目地址https://gitcode.com/gh_mirrors/ca/cat点击查看免费下载相关推荐CAT Go 客户端gocat接入指南基于 CGO 的监控埋点实践CAT Go 客户端gocat接入指南基于 CGO 的监控埋点实践 本篇技术指南围绕 CAT 监控平台的多语言客户端家族中 Go 语言实现 gocat 展可观测性指标监控告警APM后端链路追踪SurrealDB监控告警新范式基于Prometheus/Grafana的零侵入实时方案SurrealDB监控告警新范式基于Prometheus/Grafana的零侵入实时方案 SurrealDB 是一个基于 Rust 的高性能、可扩展的关系型数数据库后端分布式数据库文档数据库图数据库嵌入式数据库KV存储5个Metrics注解使用技巧零侵入式实现应用指标埋点5个Metrics注解使用技巧零侵入式实现应用指标埋点 Metrics是一个强大的Java应用监控库通过简单的注解就能实现零侵入式的指标埋点让开发者轻松掌可观测性后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门