AOT 是怎么工作的
Feat Cloud 里所谓的 AOT,不是一个抽象口号。
它的含义很具体:在编译期把一部分原本可能在运行期做的事情提前做掉,生成可直接加载的服务代码。
flowchart LR
A["源码里的 @Controller / @Bean / @Mapper"] --> B["FeatAnnotationProcessor"]
B --> C["生成 CloudService 实现"]
C --> D["写入 META-INF/services/CloudService"]
D --> E["运行期 ApplicationContext"]
E --> F["ServiceLoader 加载 CloudService"]
F --> G["加载 Bean / 注入依赖 / 注册路由"]
如果你只是正常使用 Feat Cloud,其实不需要先理解这一页。
但如果你想知道它为什么能以这种方式组织 Bean、Controller、Mapper 和运行时加载流程,这一页会有帮助。
先把问题说清楚
Section titled “先把问题说清楚”在很多常见 Java Web 框架里,运行时通常要做这些事:
- 扫描类和注解
- 解析 Controller
- 建立路由映射
- 注入依赖
- 生成或缓存一些元数据
Feat Cloud 选择把其中很大一部分提前到编译期完成。
这也是它 AOT 设计的起点。
编译期到底生成了什么
Section titled “编译期到底生成了什么”从仓库结构可以直接看出这套机制的几个关键模块:
feat-cloud-aotfeat-cloud-aot-vmfeat-cloud
其中:
feat-cloud-aot负责编译期生成代码feat-cloud负责运行期加载和执行这些服务feat-cloud-aot-vm提供一种更适合开发期的 AOT VM 运行模式
编译期最关键的入口是:
tech.smartboot.feat.cloud.aot.FeatAnnotationProcessor
它会处理 Feat Cloud 关心的注解,并生成对应的服务类和服务描述文件。
它生成的不是“元数据”,而是“可执行服务类”
Section titled “它生成的不是“元数据”,而是“可执行服务类””在 Feat Cloud 的运行模型里,最终被加载的是 CloudService 实现。
运行时的 ApplicationContext 会通过 ServiceLoader.load(CloudService.class) 去加载这些服务。
这意味着 AOT 做的核心事情不是只存一份配置,而是生成一批真正可以被运行期直接执行的类。
这也是为什么在你查看 target/generated-sources/annotations 时,会看到诸如:
UserControllerCloudServiceUserMapperCloudServiceFeatApplication
这类名字的类。
为什么这件事重要
Section titled “为什么这件事重要”如果编译期已经生成好了这些服务类,运行期就不需要再去做同样级别的动态分析。
它可以更直接地进入下面这些动作:
- 加载服务
- 初始化 Bean
- 注入依赖
- 注册路由
这会带来几个实际效果:
- 运行期逻辑更直接
- 启动过程的工作量更可控
- 对 Native Image 这类场景更友好
以 Controller 为例理解 AOT
Section titled “以 Controller 为例理解 AOT”当你写下一个普通控制器:
@Controller("users")public class UserController { @RequestMapping("/hello") public String hello() { return "hello"; }}在 Feat Cloud 的 AOT 体系里,编译期不会只记住“这里有个 Controller”。
它会生成对应的 CloudService 类,并在其中明确写出:
- 如何实例化这个 Controller
- 如何把它注册进应用上下文
- 如何把
/users/hello这条路由挂到 Router 上
所以从运行期视角看,它接手到的已经不是“一个待解析的 Controller 类”,而是“一个已经具备执行逻辑的 CloudService”。
Bean、Mapper、CloudOptions 也在做同样的事
Section titled “Bean、Mapper、CloudOptions 也在做同样的事”从 feat-cloud-aot 里的实现可以看到,AOT 处理并不只针对 Controller。
它还会围绕这些方向生成代码:
- Bean
- Mapper
- CloudOptions 相关扩展
这也是为什么 MyBatis、CloudOptions、Controller 这几块内容在 Feat Cloud 里能一起被纳入同一套编译期体系里理解。
运行期是怎么把这些东西串起来的
Section titled “运行期是怎么把这些东西串起来的”真正串联这套机制的是 ApplicationContext。
它的大致运行路径可以理解成:
- 用
ServiceLoader找到所有CloudService - 按顺序加载这些服务
- 让服务完成 Bean 加载、注入、路由注册等动作
- 最终把应用挂到运行时的 Router 和上下文里
所以从外部看你只是调用了:
FeatCloud.cloudServer().listen();但内部真正工作的,是一套已经在编译期准备好的服务装配流程。
AOT VM 是什么
Section titled “AOT VM 是什么”如果说 AOT 模式更偏向“编译期把事情做完”,那 AOT VM 更像是:
在开发期尽量保留 AOT 的使用体验,同时让调试和变更成本更低。
仓库里对应的模块是:
feat-cloud-aot-vm
从源码可以看到它提供了 AotVMCloudService 和对应的处理器实现。
它的价值不在于和 AOT 完全一样,而在于让你在开发阶段不用一直围绕最终部署形态去思考。
什么时候应该关心 AOT VM
Section titled “什么时候应该关心 AOT VM”你通常在下面这些情况下才需要认真看它:
- 你已经在使用 Feat Cloud
- 你开始关注开发期与部署期的差异
- 你希望在调试体验和最终性能之间做平衡
如果你还在 quickstart 阶段,这一层完全可以先跳过。
这套机制对你意味着什么
Section titled “这套机制对你意味着什么”从使用者角度,AOT 最重要的意义不是“编译期很高级”,而是它会影响你怎么理解下面这些事:
- 为什么 Feat Cloud 的启动过程长这样
- 为什么某些能力更适合编译期决定,而不是运行期反射
- 为什么它和传统运行期扫描框架的运行模型不一样
换句话说,这页的价值不在于教你“怎么手写 AOT”,而在于帮你理解 Feat Cloud 这套架构为什么是现在这个样子。
什么时候需要回来看这页
Section titled “什么时候需要回来看这页”这页最适合在下面这些时机阅读:
- 你已经用过 Feat Cloud,但想理解它的底层机制
- 你在看
target/generated-sources/annotations,想知道这些类为什么存在 - 你准备继续研究 Native Image 或 AOT VM 相关内容