如果你曾为 Spring AOP 的耦合问题头疼,或是厌倦了在业务代码中反复引入切面依赖,那么这篇文章可能会成为你的「解药」。今天要介绍的 FIT 框架,通过创新的 AOP 插件化设计,实现了真正的业务无侵入式开发 —— 无需改代码、无需加依赖,你的业务模块甚至不知道自己被「切面」盯上了。
传统 AOP 的困境: 代码耦合的隐形代价
AOP(面向切面编程)是解决切面关注点的利器,但传统实现方式(如 Spring AOP)存在一个致命问题:业务模块需要显式依赖切面模块。想象一下,你写了一个完美的业务逻辑,却不得不为了加一行日志引入一个切面依赖 —— 这就像为了喝杯咖啡,必须买下一个崭新的咖啡杯。
更糟糕的是,当切面逻辑需要调整时,业务代码可能被迫同步修改,耦合性和维护成本直线上升。
1. FIT 框架的「魔法」:插件化隔离
FIT 框架的解决方案是:让 AOP 成为可插拔的独立功能,而非侵入式依赖。其实现基于两项关键技术:
1.1 字节码增强技术
FIT 框架通过字节码增强技术,在运行时动态地将 AOP 逻辑织入到目标方法中。具体来说,这个过程发生在创建 Bean 时,FIT 框架会首先部署 AOP 插件,然后在业务插件部署时,将 AOP 逻辑织入匹配到的目标方法中。由于整个过程是在运行时完成的,因此用户无需修改代码即可享受 AOP 功能。
1.2 插件化架构
-
局部切面: 在插件内实现的 AOP 仅作用于当前插件,支持热插拔(Hot-Swap)。
-
全局切面: 封装为独立插件后,AOP 可全局生效(但不支持热插拔)。
开发者可根据场景自由选择,实现 「精准打击」 。
为什么全局切面插件不支持热插拔?因为字节码增强后的类一旦加载到 JVM,重新织入需要重建所有相关 Bean。FIT 选择优先保障系统稳定性,避免「热插拔全局切面」可能引发的运行时风险。
2. 实战:5 分钟实现零侵入式日志监控
2.1 准备环境
进入项目地址 FIT-Framework (http://fitframework.io),下载项目代码,根据入门指南快速部署你的 FIT 环境,并学习如何基于 FIT 框架新建属于你自己的插件!
获取本实战案例完整代码请点击:
aop-log-plugin(https://gitcode.com/ModelEngine/fit-framework/tree/main/examples/fit-example/05-aop-log-plugin)
2.2 场景需求
为所有 @GetMapping
接口自动记录方法执行耗时、参数和异常信息,且 业务模块不引入任何日志依赖。
2.3 目录构建
请根据以下目录创建工程,本目录参考了 FIT 工程目录最佳实践。
aop-log-plugin -- 总目录
+- plugins -- 插件目录,在该目录下创建各类插件
│ +- plugin-log -- 日志功能插件,在该插件内实现 AOP 逻辑
│ │ +- src
│ │ +- pom.xml
│ │ \- ...
│ +- plugin-simple-mvc -- 一个简单的 MVC 功能插件,在该插件内实现业务逻辑
│ │ +- src
│ │ +- pom.xml
│ │ \- ...
│ \- ...
+- pom.xml
+- README.xml
\- ...
Step 1:构建业务模块(完全无感知)
simple-mvc 插件
在 simple-mvc
插件内,我们实现一个简单的 MVC 功能:
定义服务:
public interface MyService {
void doSomething();
}
定义服务相关的实现,需要打上 @Component
注解将其注册为 Bean
:
@Component
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("do something");
}
}
定义一个简单的 HTTP 控制器,需要打上 @Component
注解将其注册为 Bean
:
@Component
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping(path = "/hello")
public void hello() {
this.myService.doSomething();
}
}
这样,一个简单的 MVC 插件就实现了,当该插件部署后,访问 http://localhost:8080/hello
即可调用到指定服务。
关于插件开发的相关 pom 配置及 yml 配置,请到项目内进行参考,此处不过多赘述。
关于如何启动 FIT 框架及部署插件,请参考项目的快速入门指南,此处不过多赘述。
Step 2:独立日志插件开发
在 log
插件内,我们通过 @Aspect
注解来定义一个日志管理的切面,同时打上 @Component
注解使之注册为一个 Bean
,通过 @Around("@annotation(modelengine.fit.http.annotation.GetMapping)")
来拦截 GetMapping
注解,当执行到含该注解的方法时,该切面会自动拦截方法并执行相关逻辑。在本例中,切面拦截目标方法后实现了简单的日志功能。
@Aspect(scope = Scope.GLOBAL)
@Component
public class LoggingAspect {
private static final Logger logger = Logger.get(LoggingAspect.class);
@Around("@annotation(modelengine.fit.http.annotation.GetMapping)")
public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
// 获取方法信息
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
// 记录方法开始日志
logger.info("===> {}.{}() 开始执行", className, methodName);
try {
// 执行目标方法
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - startTime;
// 记录方法结束日志
logger.info("<=== {}.{}() 执行成功 | 耗时: {}ms", className, methodName, executionTime);
return result;
} catch (Exception e) {
long executionTime = System.currentTimeMillis() - startTime;
logger.error("<=== {}.{}() 执行失败 | 耗时: {}ms | 异常: {}",
className,
methodName,
executionTime,
e.getMessage(),
e);
throw e;
}
}
}
Step 3:见证「魔法时刻」
-
将
log
插件部署到用户插件目录中。 -
启动 FIT。
-
将
simple-mvc
插件部署到用户插件目录中。 -
此时访问
http://localhost:8080/hello
,则可以在Bash
中看到如下日志:
[yyyy-MM-dd 00:00:00.000] [INFO ] [netty-request-assembler-thread-0] [modelengine.fit.example.LoggingAspect] ===> modelengine.fit.example.controller.MyController.hello() 开始执行
do something
[yyyy-MM-dd 00:00:00.000] [INFO ] [netty-request-assembler-thread-0] [modelengine.fit.example.LoggingAspect] <=== modelengine.fit.example.controller.MyController.hello() 执行成功 | 耗时: 1809ms
关于如何启动 FIT 框架及部署插件,请参考项目的快速入门指南,此处不过多赘述。
业务代码全程无感知,日志插件却已悄然完成监控 —— 这才是工程师追求的「干净架构」。
为什么开发者需要关注 FIT?
解耦神器
切面功能与业务代码物理隔离,符合「单一职责」原则。
动态能力
通过插件热插拔,可随时为系统添加 / 移除功能(如临时开启性能监控)。
微服务友好
在分布式场景下,可通过独立插件实现跨服务的统一切面管理。
探索边界:FIT 的适用场景
✅ 需要为遗留系统添加全局监控
✅ 多团队协作时避免切面代码冲突
✅ 快速构建可复用的通用能力(如日志、鉴权、限流)
结语:重新定义 AOP 的自由度
FIT 框架的插件化设计,本质上是对「代码边界」的一次重构。它让 AOP 不再是被迫引入的「外挂」,而是可自由装配的「功能模块」。
对于追求高内聚、低耦合的工程师而言,这或许正是我们期待已久的解决方案。
项目地址: FIT-Framework(http://fitframework.io)
思考题: 如果你的团队采用 FIT,你会用它解决哪些历史痛点?欢迎评论区讨论!
技术人,用代码说话,用架构思考
关注我们,探索更多「优雅解耦」的工程实践!🛠️
微信公众号: