Spring7.0的AOT解析

spring老生畅谈的两个特性,IOC、AOP,这两个已熟悉的不行;现在来感受一下目前与IOC、AOP并驾齐驱的AOT。

AOT

提前优化简介

AOT(Ahead of Time Optimizations)

AOT是一种构建时优化机制,主要针对GraalVM Native Image等原生镜像编译场景,通过在编译期分析和生成代码,减少运行时的反射、资源加载和动态连接等;从而实现更快的启动时间、更低的内存占用和更好的性能。

Spring AOT设计的核心概念为 静态化一切可静态化的部分:在构建时模拟ApplicationContext的刷新过程,提前做出运行时决策(Bean发现、条件判断),并生成优化的代码和元数据。避免运行时的动态扫描和反射调用,尤其适用于固定classpath的环境。

关键组件

  • ApplicationContextAotGenerator:AOT引擎的入口点。它接收一个 GenericApplicationContext 和 GenerationContext,负责协调整个处理流程。
  • GenerationContext:管理生成的源代码和RumtimeHints的上下文。
  • RuntimeHints:收集GraalVM 所需的运行时提示,包括反射、资源加载、序列化和代理生成。
  • BeanFactoryInitializationAotProcessor和BeanRegistrationAotProcessor:自定义处理器接口,用于在 AOT 阶段贡献代码生成和提示。

AOT的运行流程

  1. AOT专用刷新(Refresh for AOT Processing)
    1. 创建bean定义,但不实例化bean
    2. 执行BeanFactoryPostProcessor(配置解析、classpath扫描)
    3. 在构建时评估@Conditional和@profile条件
    4. 跳过大多数的BeanPostProcessor(AOP),仅处理MergedBeanDefinitionPostProcessor或SmartInstantiationAwareBeanPostProcessor
  2. BeanFactory初始化AOT
    1. 遍历所有BeanFactoryInitializationAotProcessor实现。
    2. 每个处理器基于当前BeanFactory状态生成代码和RuntimeHints
  3. 输出生成的类
    1. java源代码(如 __BeanDefinitions 类)。
    2. 字节码(动态代理)。
    3. 一个ApplicationContextInitializer的类,用来运行时初始化。
1
2
3
4
5
RuntimeHints hints = new RuntimeHints();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MyApplication.class);
context.refreshForAotProcessing(hints);  // AOT 专用刷新
// context.close();  // 注意:AOT 后需关闭上下文

AOT的限制

如无运行时 Bean 定义变更(禁止 registerSingleton)、实例供应商(lambda/method 引用)不可转换、需精确 Bean 类型等。这些设计使配置更“可预测”,但要求开发者避免动态行为。

AOT实例

AOT 将 @Configuration 等配置类转换为静态 Bean 定义,避免运行时反射。核心是通过 BeanInstanceSupplier 生成直接方法调用。

假设有一个 @Configuration 类:

1
2
3
4
5
6
7
@Configuration(proxyBeanMethods = false)
public class DataSourceConfiguration {
    @Bean
    public SimpleDataSource dataSource() {
        return new SimpleDataSource();
    }
}

AOT 生成的代码(DataSourceConfiguration__BeanDefinitions 类):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Generated
public class DataSourceConfiguration__BeanDefinitions {
    public static BeanDefinition getDataSourceConfigurationBeanDefinition() {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(DataSourceConfiguration.class);
        beanDefinition.setInstanceSupplier(DataSourceConfiguration::new);
        return beanDefinition;
    }

    private static BeanInstanceSupplier<SimpleDataSource> getDataSourceInstanceSupplier() {
        return BeanInstanceSupplier.forFactoryMethod(
            DataSourceConfiguration.class, "dataSource")
            .withGenerator(registeredBean ->
                registeredBean.getBeanFactory()
                    .getBean(DataSourceConfiguration.class)
                    .dataSource());
    }

    public static BeanDefinition getDataSourceBeanDefinition() {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(SimpleDataSource.class);
        beanDefinition.setInstanceSupplier(getDataSourceInstanceSupplier());
        return beanDefinition;
    }
}

用BeanInstanceSupplier替换了反射调用,确保注入和创建是静态的。

自定义参与通过 BeanRegistrationAotProcessor 实现,例如 AutowiredAnnotationBeanPostProcessor 会生成注入代码。处理器需通过 META-INF/spring/aot.factories 注册,或直接实现接口(但这些 Bean 会在 AOT 时初始化,需谨慎使用)。

RuntimeHints处理

AOT和GraalVM的桥梁,用来收集不可静态分析的元数据。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计