Tio Boot DocsTio Boot Docs
Home
  • java-db
  • api-table
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
Home
  • java-db
  • api-table
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
  • 01_tio-boot 简介

    • tio-boot:新一代高性能 Java Web 开发框架
    • tio-boot 入门示例
    • Tio-Boot 配置 : 现代化的配置方案
    • tio-boot 整合 Logback
    • tio-boot 整合 hotswap-classloader 实现热加载
    • 自行编译 tio-boot
    • 最新版本
    • 开发规范
  • 02_部署

    • 使用 Maven Profile 实现分环境打包 tio-boot 项目
    • Maven 项目配置详解:依赖与 Profiles 配置
    • tio-boot 打包成 FastJar
    • 使用 GraalVM 构建 tio-boot Native 程序
    • 使用 Docker 部署 tio-boot
    • 部署到 Fly.io
    • 部署到 AWS Lambda
    • 到阿里云云函数
    • 使用 Deploy 工具部署
    • 胖包与瘦包的打包与部署
    • 使用 Jenkins 部署 Tio-Boot 项目
    • 使用 Nginx 反向代理 Tio-Boot
    • 使用 Supervisor 管理 Java 应用
  • 03_配置

    • 配置参数
    • 服务器监听器
    • 内置缓存系统 AbsCache
    • 使用 Redis 作为内部 Cache
    • 静态文件处理器
    • 基于域名的静态资源隔离
    • DecodeExceptionHandler
  • 04_原理

    • 生命周期
    • 请求处理流程
    • 重要的类
  • 05_json

    • Json
    • 接受 JSON 和响应 JSON
    • 响应实体类
  • 06_web

    • 概述
    • 文件上传
    • 接收请求参数
    • 接收日期参数
    • 接收数组参数
    • 返回字符串
    • 返回文本数据
    • 返回网页
    • 请求和响应字节
    • 文件下载
    • 返回视频文件并支持断点续传
    • http Session
    • Cookie
    • HttpRequest
    • HttpResponse
    • Resps
    • RespBodyVo
    • /zh/06_web/19.html
    • 全局异常处理器
    • 异步
    • 动态 返回 CSS 实现
    • 返回图片
    • Transfer-Encoding: chunked 实时音频播放
    • Server-Sent Events (SSE)
    • 接口访问统计
    • 接口请求和响应数据记录
    • 自定义 Handler 转发请求
    • 使用 HttpForwardHandler 转发所有请求
    • 跨域
    • 添加 Controller
    • 常用工具类
    • HTTP Basic 认证
    • WebJars
    • JProtobuf
  • 07_validate

    • 数据紧校验规范
    • 参数校验
  • 08_websocket

    • 使用 tio-boot 搭建 WebSocket 服务
    • WebSocket 聊天室项目示例
  • 09_java-db

    • java‑db
    • 操作数据库入门示例
    • SQL 模板
    • 数据源配置与使用
    • ActiveRecord
    • Model
    • 生成器与 Model
    • Db 工具类
    • 批量操作
    • 数据库事务处理
    • Cache 缓存
    • Dialect 多数据库支持
    • 表关联操作
    • 复合主键
    • Oracle 支持
    • Enjoy SQL 模板
    • Java-DB 整合 Enjoy 模板最佳实践
    • 多数据源支持
    • 独立使用 ActiveRecord
    • 调用存储过程
    • java-db 整合 Guava 的 Striped 锁优化
    • 生成 SQL
    • 通过实体类操作数据库
    • java-db 读写分离
    • Spring Boot 整合 Java-DB
    • like 查询
    • 常用操作示例
    • Druid 监控集成指南
    • SQL 统计
  • 10_api-table

    • ApiTable 概述
    • 使用 ApiTable 连接 SQLite
    • 使用 ApiTable 连接 Mysql
    • 使用 ApiTable 连接 Postgres
    • 使用 ApiTable 连接 TDEngine
    • 使用 api-table 连接 oracle
    • 使用 api-table 连接 mysql and tdengine 多数据源
    • EasyExcel 导出
    • EasyExcel 导入
    • TQL(Table SQL)前端输入规范
    • ApiTable 实现增删改查
    • 数组类型
    • 单独使用 ApiTable
  • 11_aop

    • JFinal-aop
    • Aop 工具类
    • 配置
    • 配置
    • 独立使用 JFinal Aop
    • @AImport
    • 原理解析
  • 12_cache

    • Caffine
    • Jedis-redis
    • hutool RedisDS
    • Redisson
    • Caffeine and redis
    • CacheUtils 工具类
    • 使用 CacheUtils 整合 caffeine 和 redis 实现的两级缓存
    • 使用 java-db 整合 ehcache
    • 使用 java-db 整合 redis
    • Java DB Redis 相关 Api
    • redis 使用示例
  • 13_认证和权限

    • hutool-JWT
    • FixedTokenInterceptor
    • 使用内置 TokenManager 实现登录
    • 用户系统
    • 重置密码
    • 匿名登录
    • Google 登录
    • 权限校验注解
    • Sa-Token
    • sa-token 登录注册
    • StpUtil.isLogin() 源码解析
    • 短信登录
    • 移动端微信登录实现指南
    • 移动端重置密码
  • 14_i18n

    • i18n
  • 15_enjoy

    • tio-boot 整合 Enjoy 模版引擎文档
    • 引擎配置
    • 表达式
    • 指令
    • 注释
    • 原样输出
    • Shared Method 扩展
    • Shared Object 扩展
    • Extension Method 扩展
    • Spring boot 整合
    • 独立使用 Enjoy
    • tio-boot enjoy 自定义指令 localeDate
    • PromptEngine
    • Enjoy 入门示例-擎渲染大模型请求体
    • Enjoy 使用示例
  • 16_定时任务

    • Quartz 定时任务集成指南
    • 分布式定时任务 xxl-jb
    • cron4j 使用指南
  • 17_tests

    • TioBootTest 类
  • 18_tio

    • TioBootServer
    • tio-core
    • 内置 TCP 处理器
    • 独立启动 UDPServer
    • 使用内置 UDPServer
    • t-io 消息处理流程
    • tio-运行原理详解
    • TioConfig
    • ChannelContext
    • Tio 工具类
    • 业务数据绑定
    • 业务数据解绑
    • 发送数据
    • 关闭连接
    • Packet
    • 监控: 心跳
    • 监控: 客户端的流量数据
    • 监控: 单条 TCP 连接的流量数据
    • 监控: 端口的流量数据
    • 单条通道统计: ChannelStat
    • 所有通道统计: GroupStat
    • 资源共享
    • 成员排序
    • ssl
    • DecodeRunnable
    • 使用 AsynchronousSocketChannel 响应数据
    • 拉黑 IP
    • 深入解析 Tio 源码:构建高性能 Java 网络应用
  • 19_aio

    • ByteBuffer
    • AIO HTTP 服务器
    • 自定义和线程池和池化 ByteBuffer
    • AioHttpServer 应用示例 IP 属地查询
    • 手写 AIO Http 服务器
  • 20_netty

    • Netty TCP Server
    • Netty Web Socket Server
    • 使用 protoc 生成 Java 包文件
    • Netty WebSocket Server 二进制数据传输
    • Netty 组件详解
  • 21_netty-boot

    • Netty-Boot
    • 原理解析
    • 整合 Hot Reload
    • 整合 数据库
    • 整合 Redis
    • 整合 Elasticsearch
    • 整合 Dubbo
    • Listener
    • 文件上传
    • 拦截器
    • Spring Boot 整合 Netty-Boot
    • SSL 配置指南
    • ChannelInitializer
    • Reserve
  • 22_MQ

    • Mica-mqtt
    • EMQX
    • Disruptor
  • 23_tio-utils

    • tio-utils
    • HttpUtils
    • Notification
    • 邮箱
    • JSON
    • 读取文件
    • Base64
    • 上传和下载
    • Http
    • Telegram
    • RsaUtils
    • EnvUtils 使用文档
    • 系统监控
    • 毫秒并发 ID (MCID) 生成方案
  • 24_tio-http-server

    • 使用 Tio-Http-Server 搭建简单的 HTTP 服务
    • tio-boot 添加 HttpRequestHandler
    • 在 Android 上使用 tio-boot 运行 HTTP 服务
    • tio-http-server-native
    • handler 常用操作
  • 25_tio-websocket

    • WebSocket 服务器
    • WebSocket Client
  • 26_tio-im

    • 通讯协议文档
    • ChatPacket.proto 文档
    • java protobuf
    • 数据表设计
    • 创建工程
    • 登录
    • 历史消息
    • 发消息
  • 27_mybatis

    • Tio-Boot 整合 MyBatis
    • 使用配置类方式整合 MyBatis
    • 整合数据源
    • 使用 mybatis-plus 整合 tdengine
    • 整合 mybatis-plus
  • 28_mongodb

    • tio-boot 使用 mongo-java-driver 操作 mongodb
  • 29_elastic-search

    • Elasticsearch
    • JavaDB 整合 ElasticSearch
    • Elastic 工具类使用指南
    • Elastic-search 注意事项
    • ES 课程示例文档
  • 30_magic-script

    • tio-boot 整合 magic-script
  • 31_groovy

    • tio-boot 整合 Groovy
  • 32_firebase

    • 整合 google firebase
    • Firebase Storage
    • Firebase Authentication
    • 使用 Firebase Admin SDK 进行匿名用户管理与自定义状态标记
    • 导出用户
    • 注册回调
    • 登录注册
  • 33_文件存储

    • 文件上传数据表
    • 本地存储
    • 使用 AWS S3 存储文件并整合到 Tio-Boot 项目中
    • 存储文件到 腾讯 COS
  • 34_spider

    • jsoup
    • 爬取 z-lib.io 数据
    • 整合 WebMagic
    • WebMagic 示例:爬取学校课程数据
    • Playwright
    • Flexmark (Markdown 处理器)
    • tio-boot 整合 Playwright
    • 缓存网页数据
  • 36_integration_thirty_party

    • tio-boot 整合 okhttp
    • 整合 GrpahQL
    • 集成 Mailjet
    • 整合 ip2region
    • 整合 GeoLite 离线库
    • 整合 Lark 机器人指南
    • 集成 Lark Mail 实现邮件发送
    • Thymeleaf
    • Swagger
    • Clerk 验证
  • 37_dubbo

    • 概述
    • dubbo 2.6.0
    • dubbo 2.6.0 调用过程
    • dubbo 3.2.0
  • 38_spring

    • Spring Boot Web 整合 Tio Boot
    • spring-boot-starter-webflux 整合 tio-boot
    • Tio Boot 整合 Spring Boot Starter
    • Tio Boot 整合 Spring Boot Starter Data Redis 指南
  • 39_spring-cloud

    • tio-boot spring-cloud
  • 40_mysql

    • 使用 Docker 运行 MySQL
    • /zh/42_mysql/02.html
  • 41_postgresql

    • PostgreSQL 安装
    • PostgreSQL 主键自增
    • PostgreSQL 日期类型
    • Postgresql 金融类型
    • PostgreSQL 数组类型
    • PostgreSQL 全文检索
    • PostgreSQL 查询优化
    • 获取字段类型
    • PostgreSQL 向量
    • PostgreSQL 优化向量查询
    • PostgreSQL 其他
  • 43_oceanbase

    • 快速体验 OceanBase 社区版
    • 快速上手 OceanBase 数据库单机部署与管理
    • 诊断集群性能
    • 优化 SQL 性能指南
    • /zh/43_oceanbase/05.html
  • 50_media

    • JAVE 提取视频中的声音
    • Jave 提取视频中的图片
    • /zh/50_media/03.html
  • 51_asr

    • Whisper-JNI
  • 54_native-media

    • java-native-media
    • JNI 入门示例
    • mp3 拆分
    • mp4 转 mp3
    • 使用 libmp3lame 实现高质量 MP3 编码
    • Linux 编译
    • macOS 编译
    • 从 JAR 包中加载本地库文件
    • 支持的音频和视频格式
    • 任意格式转为 mp3
    • 通用格式转换
    • 通用格式拆分
    • 视频合并
    • VideoToHLS
    • split_video_to_hls 支持其他语言
    • 持久化 HLS 会话
  • 55_telegram4j

    • 数据库设计
    • /zh/55_telegram4j/02.html
    • 基于 MTProto 协议开发 Telegram 翻译机器人
    • 过滤旧消息
    • 保存机器人消息
    • 定时推送
    • 增加命令菜单
    • 使用 telegram-Client
    • 使用自定义 StoreLayout
    • 延迟测试
    • Reactor 错误处理
    • Telegram4J 常见错误处理指南
  • 56_telegram-bots

    • TelegramBots 入门指南
    • 使用工具库 telegram-bot-base 开发翻译机器人
  • 60_LLM

    • 简介
    • AI 问答
    • /zh/60_LLM/03.html
    • /zh/60_LLM/04.html
    • 增强检索(RAG)
    • 结构化数据检索
    • 搜索+AI
    • 集成第三方 API
    • 后置处理
    • 推荐问题生成
    • 连接代码执行器
    • 避免 GPT 混乱
    • /zh/60_LLM/13.html
  • 61_ai_agent

    • 数据库设计
    • 示例问题管理
    • 会话管理
    • 历史记录
    • 对接 Perplexity API
    • 意图识别与生成提示词
    • 智能问答模块设计与实现
    • 文件上传与解析文档
    • 翻译
    • 名人搜索功能实现
    • Ai studio gemini youbue 问答使用说明
    • 自建 YouTube 字幕问答系统
    • 自建 获取 youtube 字幕服务
    • 通用搜索
    • /zh/61_ai_agent/15.html
    • 16
    • 17
    • 18
    • 在 tio-boot 应用中整合 ai-agent
    • 16
  • 62_translator

    • 简介
  • 63_knowlege_base

    • 数据库设计
    • 用户登录实现
    • 模型管理
    • 知识库管理
    • 文档拆分
    • 片段向量
    • 命中测试
    • 文档管理
    • 片段管理
    • 问题管理
    • 应用管理
    • 向量检索
    • 推理问答
    • 问答模块
    • 统计分析
    • 用户管理
    • api 管理
    • 存储文件到 S3
    • 文档解析优化
    • 片段汇总
    • 段落分块与检索
    • 多文档解析
    • 对话日志
    • 检索性能优化
    • Milvus
    • 文档解析方案和费用对比
    • 离线运行向量模型
  • 64_ai-search

    • ai-search 项目简介
    • ai-search 数据库文档
    • ai-search SearxNG 搜索引擎
    • ai-search Jina Reader API
    • ai-search Jina Search API
    • ai-search 搜索、重排与读取内容
    • ai-search PDF 文件处理
    • ai-search 推理问答
    • Google Custom Search JSON API
    • ai-search 意图识别
    • ai-search 问题重写
    • ai-search 系统 API 接口 WebSocket 版本
    • ai-search 搜索代码实现 WebSocket 版本
    • ai-search 生成建议问
    • ai-search 生成问题标题
    • ai-search 历史记录
    • Discover API
    • 翻译
    • Tavily Search API 文档
    • 对接 Tavily Search
    • 火山引擎 DeepSeek
    • 对接 火山引擎 DeepSeek
    • ai-search 搜索代码实现 SSE 版本
    • jar 包部署
    • Docker 部署
    • 爬取一个静态网站的所有数据
    • 网页数据预处理
    • 网页数据检索与问答流程整合
  • 65_java-linux

    • Java 执行 python 代码
    • 通过大模型执行 Python 代码
    • MCP 协议
    • Cline 提示词
    • Cline 提示词-中文版本
  • 66_manim

    • 简介
    • Manim 开发环境搭建
    • 生成场景提示词
    • 生成代码
    • 完整脚本示例
    • 语音合成系统
    • Fish.audio TTS 接口说明文档与 Java 客户端封装
    • 整合 fishaudio 到 java-uni-ai-server 项目
    • 执行 Python (Manim) 代码
    • 使用 SSE 流式传输生成进度的实现文档
    • 整合全流程完整文档
    • HLS 动态推流技术文档
    • manim 分场景生成代码
    • 分场景运行代码及流式播放支持
    • 分场景业务端完整实现流程
    • Maiim布局管理器
    • 仅仅生成场景代码
    • 使用 modal 运行 manim 代码
    • Python 使用 Modal GPU 加速渲染
    • Modal 平台 GPU 环境下运行 Manim
    • Modal Manim OpenGL 安装与使用
    • 优化 GPU 加速
    • 生成视频封面流程
    • Java 调用 manim 命令 执行代码 生成封面
    • Manim 图像生成服务客户端文档
    • manim render help
    • 显示 中文公式
    • manimgl
    • EGL
    • /zh/66_manim/30.html
    • /zh/66_manim/31.html
    • 成本核算
    • /zh/66_manim/33.html
  • 70_tio-boot-admin

    • 入门指南
    • 初始化数据
    • token 存储
    • 与前端集成
    • 文件上传
    • 网络请求
    • 图片管理
    • /zh/70_tio-boot-admin/08.html
    • Word 管理
    • PDF 管理
    • 文章管理
    • 富文本编辑器
  • 71_tio-boot

    • /zh/71_tio-boot/01.html
    • Swagger 整合到 Tio-Boot 中的指南
    • HTTP/1.1 Pipelining 性能测试报告
  • 80_性能测试

    • 压力测试 - tio-http-serer
    • 压力测试 - tio-boot
    • 压力测试 - tio-boot-native
    • 压力测试 - netty-boot
    • 性能测试对比
    • TechEmpower FrameworkBenchmarks
    • 压力测试 - tio-boot 12 C 32G
  • 99_案例

    • 封装 IP 查询服务
    • tio-boot 案例 - 全局异常捕获与企业微信群通知
    • tio-boot 案例 - 文件上传和下载
    • tio-boot 案例 - 整合 ant design pro 增删改查
    • tio-boot 案例 - 流失响应
    • tio-boot 案例 - 增强检索
    • tio-boot 案例 - 整合 function call
    • tio-boot 案例 - 定时任务 监控 PostgreSQL、Redis 和 Elasticsearch
    • Tio-Boot 案例:使用 SQLite 整合到登录注册系统
    • tio-boot 案例 - 执行 shell 命令

原理解析

1. 简介

本文介绍了 JFinal 框架中 AOP(面向切面编程)的实现原理和整体架构。

1.1. AOP 简介

AOP(Aspect-Oriented Programming,面向切面编程)是一种通过预编译方式和运行期间动态代理实现程序功能统一维护的技术。它允许将系统中的横切关注点(如日志、事务管理、权限控制等)与业务逻辑分离,增强代码的可维护性和可重用性。

传统的 AOP 实现通常需要引入大量复杂且冗余的概念,例如:Aspect(切面)、Advice(通知)、Joinpoint(连接点)、Pointcut(切入点)、Introduction(引入)、Weaving(织入)、Around(环绕通知)等。同时,还需要引入 IoC 容器,并配合大量的 XML 配置或注解来进行组件装配。

这种传统方式不仅学习成本高、开发效率低、开发体验差,而且还会影响系统性能,特别是在开发阶段可能导致项目启动缓慢,极大地影响开发效率。

JFinal 采用了极简化的 AOP 设计,专注于 AOP 最核心的目标,将概念减少到极致,仅有三个核心概念:Interceptor(拦截器)、Before(前置通知)、Clear(清除拦截器)。同时,无需引入 IoC 容器,也无需使用繁琐的 XML 配置。

1.2. 核心概念

JFinal 实现的 AOP 只有三个核心概念,理解和使用相对简单:

  • Interceptor(拦截器):用于拦截方法调用,并提供机会在方法的前后添加切面代码,实现 AOP 的核心功能。
  • Before(前置通知):用于配置拦截器的注解,可在类或方法级别进行配置,指定哪些拦截器应用于哪些类或方法。
  • Clear(清除拦截器):拦截器按照 Global(全局)、Routes(路由)、Class(类)、Method(方法)四个层次依次生效。Clear 注解用于清除自身所处层次以上层的拦截器。

1.3. 使用方式

使用 JFinal 的 AOP 只需三步:

  1. 在方法上使用 @Before(InterceptorClass.class) 注解,指定要应用的拦截器。
  2. 在属性上使用 @Inject 注解,实现依赖注入。
  3. 使用 Aop.get() 获取增强后的实例。

示例代码:

// 主服务类
@Slf4j
public class Service {
    @Inject
    private OtherService otherService;

    @Before(ServiceInterceptor.class)
    public void doIt() {
        log.info("doIt");
    }

    public static class ServiceInterceptor implements AopInterceptor {
        @Override
        public void intercept(AopInvocation inv) {
            log.info("before ServiceInterceptor");
            inv.invoke();
            log.info("after ServiceInterceptor");
        }
    }
}

// 被注入的服务类
@Slf4j
public class OtherService {
    @Before(OtherInterceptor.class)
    public void doOther() {
        log.info("doOther");
    }

    public static class OtherInterceptor implements AopInterceptor {
        @Override
        public void intercept(AopInvocation inv) {
            log.info("before OtherInterceptor");
            inv.invoke();
            log.info("after OtherInterceptor");
        }
    }
}

// 测试类
public class AopDemo {
    public static void main(String[] args) {
        ProxyManager.me().setPrintGeneratedClassToConsole(true);
        Service service = Aop.get(Service.class);
        service.doIt();
    }
}

在上述代码中,我们:

  • 使用了 @Before 注解为方法配置了拦截器。
  • 使用了 @Inject 注解实现了依赖注入。
  • 通过 Aop.get(Service.class) 获取了增强后的 Service 实例。

2. 实现原理

2.1. JFinal 原生实现

JFinal 的原生 AOP 实现主要步骤如下(参见 ProxyFactory):

  1. 解析被增强类的 Class:读取需要增强的类的元数据信息。
  2. 生成增强类的 Java 代码:根据模板生成包含切面逻辑的 Java 代码。
  3. 编译生成的 Java 代码:将生成的代码编译成字节码。
  4. 加载增强后的 Class 文件:将编译后的类加载到 JVM 中。
  5. 反射生成增强类的实例:使用反射创建增强类的对象。
  6. 依赖注入:根据 @Inject 注解对属性进行依赖注入。

关键步骤是根据模板生成被增强类的 Java 代码。生成的代码示例如下:

AopInvocation 构造方法

public AopInvocation(Object target, Long proxyMethodKey, Callback callback, Object... args)
package com.example.demo.jfinal;

import com.jfinal.aop.AopInvocation;

public class Service$$EnhancerByJFinal extends Service {
    @Override
    public void doIt() {
        AopInvocation inv = new AopInvocation(this, 1L,
            args -> {
                Service$$EnhancerByJFinal.super.doIt();
                return null;
            }
        );
        inv.invoke();
    }
}

可以看到,生成的增强类中构建了一个 AopInvocation 对象,并调用了其 invoke() 方法。实际上,所有的执行逻辑都封装在 AopInvocation 中,自动生成的增强类只是一个代理层。

2.2. CGLIB 实现

使用 CGLIB 实现 AOP 的原理相对简单,通过调用 CGLIB 提供的 API 即可:

public <T> T get(Class<T> target) {
    return (T) net.sf.cglib.proxy.Enhancer.create(target, new CglibCallback());
}

// CglibProxyFactory 的核心就是调用 CGLIB 对目标类进行增强,切面逻辑在 CglibCallback 中实现。

/**
 * CglibCallback 实现方法拦截。
 */
class CglibCallback implements MethodInterceptor {
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 1. 构建拦截器链
        MethodKey key = IntersCache.getMethodKey(targetClass, method);
        Interceptor[] inters = IntersCache.get(key);
        if (inters == null) {
            inters = interMan.buildServiceMethodInterceptor(targetClass, method);
            IntersCache.put(key, inters);
        }

        // 2. 封装 AopInvocation 并执行
        AopInvocation inv = new AopInvocation(target, method, inters,
            x -> methodProxy.invokeSuper(target, x),
            args
        );
        inv.invoke();
        return inv.getReturnValue();
    }
}

这段代码主要展示了如何使用 CGLIB 库创建一个代理对象,并通过 CglibCallback 类实现方法调用的拦截和处理。

可以看出,CGLIB 实现的增强逻辑与原生实现一致,都是构建 AopInvocation 并执行。不同之处在于:

  • 原生实现中,通过 ProxyMethod 获取拦截器链。
  • CGLIB 实现中,使用 InterceptorManager 构建拦截器链。

2.3. AopInvocation 实现织入逻辑

初始化:

// 构造方法
public AopInvocation(Object target, Long proxyMethodKey, Callback callback) {
    this(target, proxyMethodKey, callback, NULL_ARGS);
}

public AopInvocation(Object target, Long proxyMethodKey, Callback callback, Object... args) {
    this.action = null;
    this.target = target;

    ProxyMethod proxyMethod = ProxyMethodCache.get(proxyMethodKey);
    this.method = proxyMethod.getMethod();
    this.inters = proxyMethod.getInterceptors();

    this.callback = callback;
    this.args = args;
}

在构造方法中,通过 ProxyMethod 获取了方法和对应的拦截器列表。这种设计思想是根据类和方法上的 @Before 注解构建拦截器链。

执行逻辑:

public void invoke() {
    if (index < inters.length) {
        inters[index++].intercept(this);
    } else if (index++ == inters.length) { // 确保 action 只执行一次
        try {
            // 执行原始方法
            if (action != null) {
                returnValue = action.getMethod().invoke(target, args);
            }
            // 执行回调
            else {
                returnValue = callback.call(args);
            }
        } catch (AopInvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t == null) {
                t = e;
            }
            throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
}

执行逻辑相对简单:

  • 如果存在拦截器,先逐个执行拦截器的 intercept() 方法。
  • 拦截器执行完毕后,执行原始方法或回调。

这种链式调用的方式确保了拦截器能够在方法调用前后添加额外的逻辑,实现 AOP 的核心功能。

3. 时序图

图1
图 1:AOP 执行时序图

配置态

  1. get 方法调用 (1-2):

    • Aop 层发起 get 方法调用,以获取增强后的 Service 对象实例。
  2. 生成代理类 (3-10):

    • 调用 Proxy 模块进行代理类的生成。
      • 构建 ProxyMethod (4):Proxy 模块会根据目标类的方法创建 ProxyMethod 实例,包含方法的元数据和拦截器列表。
      • 生成字节码 (5-6):ProxyGenerator 利用模板生成包含切面逻辑的 Java 源代码并转换为字符串形式。
      • 编译生成的 Java 字节码 (7-8):ProxyCompiler 负责编译生成的 Java 源代码,将其转化为 JVM 可执行的字节码。
      • 加载增强类 (9):使用 ProxyClassLoader 将编译后的字节码加载到 JVM 中,生成增强后的代理类。
    • 得到增强后的类 (10):增强类生成后,将其返回给 Aop。
  3. 依赖注入 (11-12):

    • Aop 调用 doInject 方法,对生成的代理对象进行依赖注入,将必要的依赖对象注入到对象中。
    • 注入完成的对象 (13):注入完成后,返回增强并完成注入的 Service 实例。

运行态

  1. 方法调用 (14-15):

    • Service 实例调用某个业务方法,触发拦截器逻辑。
    • 生成增强对象并调用方法。
  2. 获取拦截器链 (16-17):

    • 调用 getInterceptors 方法,获取应用于该方法的拦截器链列表。
  3. 方法调用封装与执行 (18-19):

    • 构建 Invocation 实例,封装方法调用的信息和拦截器链。
    • 调用 invoke 方法,依次执行拦截器逻辑。
  4. 执行拦截器 (20-21):

    • intercept (20):每个拦截器依次执行,并在调用前后执行切面逻辑(如日志、权限检查等)。
    • call 原始方法 (21):当所有拦截器执行完毕后,调用实际的业务方法。
  5. 返回结果 (22-23):

    • 方法执行结束后,将执行结果返回给调用方。

总结

整个流程中,JFinal 的 AOP 通过生成代理类来增强对象,并在方法执行前后插入拦截器逻辑。配置态主要涉及生成和编译增强类,而运行态则主要是拦截器链的构建与执行,从而实现方法的前后切面逻辑。

这个设计极大地简化了 AOP 的实现过程,不需要复杂的 XML 配置和 IoC 容器支持,只需基于注解即可完成拦截器的配置与依赖注入,提升了开发体验和运行时性能。

4. 架构

整体架构

整个架构分为两层:Aop 层和 Proxy 层。

  • Proxy 层:负责获取增强后的类对象,包括生成增强的 Java 代码、编译、加载类等。
  • Aop 层:使用 Proxy 层增强后的代码,组装拦截器链,实现拦截逻辑。

图2
图 2:JFinal AOP 整体架构图

Proxy 模块

图3
图 3:Proxy 模块类图

类图说明:

  • 对外接口:
    • Proxy:提供 get 方法,根据类获取增强后的实例。
  • 内部实现:
    • ProxyFactory:Proxy 接口的实现类。
  • 配置类:
    • ProxyManager:Proxy 模块的配置类。
  • 功能实现类:
    • ProxyGenerator:代码生成器,生成增强类的 Java 代码。
    • ProxyCompiler:代码编译器,编译生成的 Java 代码。
    • ProxyClassLoader:类加载器,加载编译后的类。
  • 实体类:
    • ProxyClass:保存被代理类的元信息。
    • ProxyMethod:保存被代理的方法和方法上的拦截器。
    • ProxyMethodCache:缓存 ProxyMethod,供 AopInvocation 根据 proxyMethodKey 获取。

Aop 模块

图4
图 4:Aop 模块类图

类图说明:

  • 对外接口:
    • Aop:
      • get:获取增强后的实例。
      • inject:注入依赖。
  • 内部实现:
    • AopFactory:Aop 接口的实现类。
  • 配置类:
    • AopManager:Aop 模块的配置类。
  • 功能实现类:
    • 利用 Proxy 模块的功能实现切面能力。
  • 实体类:
    • AopInvocation:封装一次方法调用,执行拦截器逻辑。
    • Interceptor:拦截器接口。
    • InterceptorManager:构建目标类的拦截器列表。

5. 总结

JFinal 的 AOP 实现核心在于构建 AopInvocation。通过生成并编译 Java 代码的方式生成增强类,或者使用 CGLIB 对目标类进行增强。

按照对外接口、配置类、接口实现类、功能实现类和实体类对 JFinal 的类进行分类,可以清晰地了解其整体架构。

Edit this page
Last Updated:
Contributors: Tong Li
Prev
@AImport