- 后端
【免费下载链接】COLA
🥤 COLA: Clean Object-oriented & Layered Architecture
本文围绕 COLA 开源仓库中的 CatchAndLog(catch-log-starter)组件展开,讲解如何通过「注解 + AOP + Spring Boot 自动装配」为 Service 层方法提供统一的请求日志、响应日志与异常处理能力。读完本文,你将掌握该组件的底层原理(切点定义、环绕通知、异常分类与响应适配)、三步接入方法(加注解、开 DEBUG、看日志),以及如何借助仓库内置的 Starter 组件 Archetype 一键生成自己的 Spring Boot Starter。
组件定位:面向 Service 层的「日志 + 异常」一体化 Starter
组件原文档开门见山地给出了它的定位:
通过注解 AOP,提供 service 级别的 logging 和 exception 处理。
也就是说,它解决的是应用中最常见也最容易被忽视的两类横切问题:每个 Service 方法都要打印入参/出参/耗时日志,以及异常抛到上层前需要一个统一的处理出口(记录日志、转成约定的错误响应返回给调用方)。这两件事如果散落在每个方法里手写,代码会极其冗长且难以维护;而用注解 + AOP 收敛到切面里,业务代码可以保持干净。
在 COLA 仓库中,该组件对应两个形态:
- 实际可用的组件:cola-component-catchlog-starter,坐标
com.alibaba.cola:cola-component-catchlog-starter; - Archetype 模板:本文关联文档正是位于 cola-starter-component-archetype 模板中的 README,模板内嵌了一套最小可运行的 starter 示例代码(CatchAndLog 注解、CatchLogAspect 切面、CatchLogAutoConfiguration 自动配置、spring.factories 等),用于指导开发者照着实现自己的 Starter 组件。
一、原理:注解 + AOP 切面 + Spring Boot 自动装配
整个组件的原理可以从三个层面拆解:
1. 一个注解标记目标类
CatchAndLog.java 是一个运行时注解,可同时标注在类和方法上:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface CatchAndLog { }标注在类上时,表示该类下所有匹配的 public 方法都会被拦截(这也是文档中在GrouponServiceImpl类级别使用的原因);标注在方法上则可做到更细粒度的控制。
2. 一个切面做环绕拦截
CatchLogAspect.java 定义了切点与环绕通知:
@Pointcut("@within(CatchAndLog) && execution(public * *(..))") public void pointcut() { } @Around(value = "pointcut()") public Object around(ProceedingJoinPoint joinPoint) { long startTime = System.currentTimeMillis(); logRequest(joinPoint); Object response = null; try { response = joinPoint.proceed(); } catch (Throwable e) { response = handleException(joinPoint, e); } finally { logResponse(startTime, response); } return response; }切点表达式@within(CatchAndLog) && execution(public * *(..))的含义是:凡是标注了@CatchAndLog的类型(@within)内部的 public 方法都会被拦截。环绕逻辑是标准的 AOP 套路:
- 先记录请求(方法签名 + 入参,通过 fastjson 序列化);
- 执行目标方法
proceed(); - 若抛出异常,交给
handleException统一转换为返回值(详见下文「异常处理」); - 无论成功失败,在
finally中记录响应与耗时。
Archetype 模板中的 CatchLogAspect.java 与仓库正式组件的实现思路完全一致,模板版本为了演示对异常处理保留了//Dummy implementation占位,正式组件则补充了完整的异常分级与响应转换逻辑。
3. 自动配置机制自动注入切面 Bean
依赖 Spring Boot 的 autoConfig 机制,组件无需任何手动配置即可生效。核心在 CatchLogAutoConfiguration.java:
@Configuration @EnableAspectJAutoProxy public class CatchLogAutoConfiguration { @Bean @ConditionalOnMissingBean(CatchLogAspect.class) public CatchLogAspect catchLogAspect() { return new CatchLogAspect(); } }关键点有两个:
@EnableAspectJAutoProxy开启 AspectJ 自动代理,是切面生效的前提;@ConditionalOnMissingBean(CatchLogAspect.class)允许使用者自定义自己的CatchLogAspectBean 来覆盖默认切面,实现按需定制。
自动配置类的注册入口在 Archetype 模板的 spring.factories 中:
org.springframework.boot.autoconfigure.EnableAutoConfiguration = ${package}.CatchLogAutoConfiguration即通过 Spring Boot 的spring.factories机制,将自动配置类登记到EnableAutoConfiguration列表中,应用启动时由 Spring Boot 自动加载(${package}是 Archetype 生成时被替换的占位符)。
二、快速接入:一行依赖即可生效
因为采用 autoConfig 机制,使用者只需添加依赖,连@EnableXXX开关注解都不需要:
<dependency> <groupId>com.alibaba.lst.tech.shared</groupId> <artifactId>catch-log-starter</artifactId> </dependency>说明:上面的坐标是组件原文档中记载的阿里内部共享坐标;在 COLA 开源仓库中,对应的发布坐标是
com.alibaba.cola:cola-component-catchlog-starter,见 cola-component-catchlog-starter/pom.xml。
从 pom.xml 可以看到组件底层依赖的构成,理解它有助于预判类路径冲突:
| 依赖 | 作用 | scope |
|---|---|---|
spring-boot-autoconfigure | 提供@ConditionalOnMissingBean等自动装配支持 | provided |
spring-boot-starter-aop | 提供 AOP 运行时(AspectJ、代理) | compile |
com.alibaba:fastjson | 入参/出参的 JSON 序列化 | provided |
org.slf4j:slf4j-api | 日志门面 | compile |
cola-component-dto | 提供Response等返回值类型 | compile |
cola-component-exception | 提供BizException/SysException异常体系 | compile |
三、使用步骤:三步完成接入
步骤 1:在 Service 类上添加 @CatchAndLog 注解
@CatchAndLog public class GrouponServiceImpl implements GrouponService { // 类的所有 public 方法自动获得日志 + 异常处理能力 }步骤 2:为组件开启 DEBUG 级日志输出
CatchLogAspect 的日志全部打在DEBUG级别(详见下文日志行说明),因此默认日志配置下是看不到的。在logback-test.xml(或项目自己的 logback 配置)中加入:
<!--这个是统一异常处理,日志记录组件的日志--> <logger name="com.alibaba.cola.catchlog" level="DEBUG"/>Archetype 模板自带的 logback-test.xml 就是标准做法:root 保持 INFO,仅将组件包名(模板中为${package},即生成工程自己的包)设为 DEBUG。生产环境建议同样只对需要排查的包开 DEBUG,避免全量 DEBUG 刷屏。
步骤 3:通过控制台日志验证 AOP 拦截已生效
文档给出了预期的控制台输出:
DEBUG c.a.l.t.s.catchlog.CatchLogAspect - Start processing: GrouponServiceImpl.queryGrouponItemDetail(..) DEBUG c.a.l.t.s.catchlog.CatchLogAspect - REQUEST : 257 DEBUG c.a.l.t.s.catchlog.CatchLogAspect - RESPONSE : {"errCode":"UNKNOWN_ERROR"...} DEBUG c.a.l.t.s.catchlog.CatchLogAspect - COST : 1329ms各行的业务含义分别是:被拦截的方法签名、序列化后的请求入参、序列化后的响应体、方法执行耗时(毫秒)。只要看到这四类日志,就说明 CatchAndLog 已经在做 AOP 拦截。
对照当前仓库源码 CatchLogAspect.java,实际输出的日志格式与文档示例略有差异(新版本统一为大写前缀并改用 SLF4J 占位符):
START PROCESSING: GrouponServiceImpl.queryGrouponItemDetail(..) REQUEST: {"id":257} RESPONSE: {"success":false,"errCode":"UNKNOWN_ERROR",...} COST: 1329ms另外两点值得注意的实现细节:
- 入参序列化使用了
SerializerFeature.IgnoreErrorGetter,遇到 getter 抛异常的字段不会拖垮整个日志; - 序列化、日志记录本身都包裹在 try-catch 中并「吞掉」异常,保证日志逻辑永远不影响业务主流程。
四、异常处理的统一出口:ResponseHandler 机制
文档特别强调组件「兼容普通的 HSF service 和 Mtop service」,并给出了ResponseHandler的设计示意:
public class ResponseHandler { public static Object handle(Class returnType, String errCode, String errMsg){ if (isColaResponse(returnType)){ return handleColaResponse(returnType, errCode, errMsg); } if(isMtopResponse(returnType)){ return handleMtopResponse(returnType, errCode, errMsg); } return null; } ... }其核心思想是:异常被捕获后,要根据方法的返回类型,构造一个「携带错误码与错误信息的响应对象」返回给调用方,而不是让异常直接冒泡。这样不同的服务协议(COLA Response、Mtop Response 等)都能获得与自己约定格式一致的错误结果。
当前仓库的实现形态
开源仓库将这一设计落地为三个协作类:
- ResponseHandlerI.java:处理器的统一接口;
- DefaultResponseHandler.java:默认实现,当前内置了COLA Response 分支——当方法返回类型是
Response或其子类(returnType == Response.class || returnType.getGenericSuperclass() == Response.class)时,通过反射newInstance()构造响应对象,填充success=false、errCode、errMessage后返回;文档中的 Mtop 分支为原 README 展示的扩展方向,开源默认实现未内置; - ResponseHandlerFactory.java:工厂类,优先从 Spring 容器中取自定义的
ResponseHandlerIBean,取不到才回退到DefaultResponseHandler。
也就是说,你完全可以像测试用例 CustomResponseHandler.java 那样,实现ResponseHandlerI并注册为 Spring Bean,即可替换默认的错误响应构造逻辑——这正是「兼容多种 service 协议」的扩展点所在。
异常分级:BizException 与 SysException
切面中 handleException 对异常做了三档分类,对应 COLA 的异常体系(cola-component-exception):
| 异常类型 | 日志级别 | 语义 | 默认错误码 |
|---|---|---|---|
BizException | WARN(DEBUG 时打印堆栈) | 已知业务异常,无需重试 | BIZ_ERROR |
SysException | ERROR(含堆栈) | 系统异常,重试可能成功 | SYS_ERROR |
其他Throwable | ERROR(含堆栈) | 未知异常 | UNKNOWN_ERROR |
三种情况最终都会交给ResponseHandlerFactory.get().handle(returnType, errCode, errMessage)构造带错误码的响应返回。文档日志示例中的{"errCode":"UNKNOWN_ERROR"...}正是「未知异常 + 响应转换」两条链路共同作用的结果。
五、进阶:用 Archetype 一键生成自己的 Starter 组件
文档所在的 cola-starter-component-archetype 是 COLA 为「快速创建 components 工程」提供的 Maven Archetype 模板(dev-util-archetypes 说明),模板内嵌了本文前面讲到的全套最小实现:注解、切面、自动配置、spring.factories、测试配置与启动类。利用它,可以把这个「日志 + 异常」组件的骨架原样复刻到自己的组件中。
archetype-metadata.xml 声明了生成的内容:src/main/java下的 Java 源码(按包名 packaged 并过滤占位符)、src/main/resources下的 spring.factories、src/test下的测试工程。生成时package、artifactId等占位符会被替换为用户指定值。
仓库还提供了封装脚本 new-cola-starter-component.sh,核心命令逻辑等价于:
mvn archetype:generate \ -DgroupId=<组件组名> \ -DartifactId="cola-component-<name>-starter" \ -Dpackage="com.alibaba.cola.<name>" \ -DarchetypeGroupId=<archetype groupId> \ -DarchetypeArtifactId=cola-starter-component-archetype \ -DarchetypeVersion=<archetype version> \ -DinteractiveMode=false \ -DarchetypeCatalog=local执行后即得到一个与cola-component-catchlog-starter同构的新 Starter 工程:CatchAndLog注解 +CatchLogAspect切面 +CatchLogAutoConfiguration自动配置 +spring.factories注册入口,稍加改造即可变成你自己的横切组件。
六、测试验证:多场景覆盖
组件的正确性由测试用例完整覆盖。CatchLogTest.java 中的用例场景包括:
- 普通方法调用(
testAspect); - 带请求参数调用(
testCatchAndLog); - 返回
Response类型(testExecuteWithResponse); - 返回 void(
testExecuteWithVoid); - 抛出
BizException且返回Response(testExecuteWithBizExceptionAndResponse); - 抛出
SysException且返回Response(testExecuteWithSysExceptionAndResponse); - 未知
RuntimeException与 void/Response 组合。
这些场景由 Demo.java 提供(一个标注了@CatchAndLog的演示 Bean),覆盖了「成功、业务异常、系统异常、未知异常」与「void、COLA Response」的交叉组合,正好验证了前文讲到的异常分级与按返回类型适配响应的行为。
小结
CatchAndLog 组件用最少的注解侵入,把 Service 层普遍存在的日志记录与异常处理收敛到一处:@CatchAndLog负责标记、CatchLogAspect负责拦截记录、ResponseHandlerI负责按返回类型转换错误响应、BizException/SysException负责异常分级,再配合 Spring Boot autoConfig 做到零配置接入。如果在自己的项目中遇到了「每个 Service 方法都在重复打日志、重复 catch 异常」的痛点,参照本文的接入三步与 cola-component-catchlog-starter 源码,即可快速落地一套统一的 Service 层横切能力。
- 后端
【免费下载链接】COLA
🥤 COLA: Clean Object-oriented & Layered Architecture
相关推荐
COLA 组件实战:cola-component-catchlog-starter 注解式 AOP 日志与异常处理详解
COLA 组件实战:cola component catchlog starter 注解式 AOP 日志与异常处理详解 导读 本文围绕 COLA(Clean O
后端mall4j 系统日志实战:基于 @SysLog 注解与 AOP 切面的后台操作审计方案
mall4j 系统日志实战:基于 @SysLog 注解与 AOP 切面的后台操作审计方案 本文以 mall4j 电商商城项目的后台管理系统为例,深入讲解如何通过
电商后端前端移动开发告别重复代码:COLA框架@CatchAndLog与@Extension注解的实战指南
告别重复代码:COLA框架@CatchAndLog与@Extension注解的实战指南 在日常开发中,你是否还在为每个接口重复编写异常捕获和日志记录代码?是否在
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考