FIT 框架:AOP 插件化,让业务代码彻底「无感」的工程革命

如果你曾为 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

@Componentpublic class MyServiceImpl implements MyService {
  
      @Override    public void doSomething() {
  
          System.out.println("do something");    }}

定义一个简单的 HTTP 控制器,需要打上 @Component注解将其注册为 Bean

@Componentpublic 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)@Componentpublic 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:见证「魔法时刻」

  1. 将 log 插件部署到用户插件目录中。

  2. 启动 FIT。

  3. 将 simple-mvc 插件部署到用户插件目录中。

  4. 此时访问 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,你会用它解决哪些历史痛点?欢迎评论区讨论!


技术人,用代码说话,用架构思考

关注我们,探索更多「优雅解耦」的工程实践!🛠️

微信公众号:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值