Spring Boot 3的AOT(GraalVM Native Image)应用开发

GraalVM Native Images是一个利用AOT(Ahead-of-Time)技术把java程序直接编译成可执行程序的编译工具,编译出来的程序在运行时不再依赖JRE,同时启动速度快,资源消耗低,这对传统java程序来说都是极大的优势。同时云原生应用来说,GraalVM Native Images编译生成的程序体积很小,非常适合云原生环境,目前由于传统java程序生成的镜像中需要包含一个体积很大的JRE或JDK而经常被人诟病。
Spring Boot从3.0版本开始支持AOT技术。
具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-native

一、概述

Spring Boot 3.0 仍然支持传统的开发方式,既编译生成jar包,通过JRE来执行,在此基础上,通过调整编译方式,可以编译生成直接运行的可执行程序,Spring AOT与传统应用的区别包括:

  1. 程序运行时动态调整的资源无法直接使用,例如反射、动态代理等,需要在代码中通过Hint为编译器指定
  2. 应用的classpath在编译后就固定了,不能动态调整
  3. 类不会延迟加载(lazy loading),应用启动时一次性加载完成
  4. 部分java切面(AOP)技术不支持

二、项目中加入依赖

在项目的gradle中增加依赖关系。

Gradle:

plugins {
    id 'org.springframework.boot' version '3.0.0'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'org.graalvm.buildtools.native' version '0.9.18'
    id 'java'
}

group = 'cn.springcamp'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    testCompileOnly {
        extendsFrom testAnnotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

与传统Spring Boot应用相比,gradle文件中增加了 org.graalvm.buildtools.native 这个plugin,其它的没有区别。

由于 org.graalvm.buildtools.native 这个plugin没有发布到 Gradle Plugin Portal 中,参照 https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html,因此需要在 settings.gradle 指定仓库地址:

settings.gradle

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

三、主要程序代码

示例程序提供了一个rest接口,该接口从数据库中读取数据。为了便于演示,使用H2数据库。

Application程序代码:

@RestController
@SpringBootApplication
public class Application {
    @Autowired
    private DbService dbService;

    @RequestMapping("/hello")
    public DemoData hello() {
        return dbService.hello();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

DbService代码:

@Component
public class DbService {
    @Autowired
    private TestDataRepository testDataRepository;

    public DemoData hello() {
        DemoData demoData = new DemoData();
        demoData = testDataRepository.save(demoData);
        return demoData;
    }
}

由于程序中没有使用反射,所以代码跟传统程序没有什么区别。

三、编译 Native Image

Spring Boot 编译 Native Image 支持2种方式,一种通过Docker进行编译,需要本地安装Docker。另外一种是用本地的编译环境进行编译,需要安装Visual Studio。
由于第一种方式比较简单,除了要安装Docker外没有很复杂的操作,本文只介绍第二种方式。

3.1 安装编译环境

需要安装 GraalVM 和 Visual Studio 两个编译工具。
GraalVM可以直接下载安装,下载地址 ,也可以通过 Scoop 进行安装。
Visual Studio 需要下载安装,由于Visual Studio体积比较大,也可以只安装 Visual Studio Build Tools

3.2 执行编译命令

由于windows命令行工具有命令长度限制,因此编译命令不能在windows命令行工具中直接执行(包括powershell和cmd),需要在安装好的Visual Studio命令行工具(x64 Native Tools Command Prompt for VS 2022)中执行。
执行命令:

gradle nativeCompile

编译生成的可执行程序在当前工程目录的 build\native\nativeCompile目录中,可以看到一个与工程名相同的以exe后缀结尾的文件。
直接运行该文件,就能体验到java程序的启动速度竟然能如此之快。
传统应用启动速度:

cn.springcamp.springnative.Application   : Started Application in 2.927 seconds (process running for 3.642)

native应用启动速度:

cn.springcamp.springnative.Application   : Started Application in 0.134 seconds (process running for 0.141)

启动速度从 3.642 提升到了 0.141 秒。

启动速度虽然快了,但是编译耗时也多了不少,这是一个缺点。

四、单元测试

传统的Spring Boot单元测试技术仍然可以使用。 Spring Boot单元测试技术在这篇文章中有专门介绍。
需要注意的是 Spring Native不支持JUnit4,需要使用JUnit5。

单元测试代码:

@Slf4j
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApplicationTest {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testHello() {
        String resp = testRestTemplate.getForObject("/hello", String.class);
        log.info("hello result : {}" + resp);
        assertThat(resp, is("{\"id\":1}"));
    }
}

通过传统单元测试技术可以验证代码业务逻辑是正常的,对于编译成 Native Image 后程序是否还能正常运行,传统单元测试技术保证不了,需要进一步使用 Native Image 单元测试。

Native Image 单元测试通过以下命令执行:

gradle nativeTest

该命令会首先把应用编译成 Native Image 可执行程序,再跑单元测试用例。由于 Native Image 编译相比传统应用耗时要长很多,所以先通过传统的Spring Boot单元测试技术保证代码业务逻辑正常后,再使用 Native Image 单元测试命令,减少整个开发流程的耗时。

回答: Spring Boot AOT (Ahead-Of-Time Compilation) 是指在Spring Boot应用程序启动之前将Java字节码编译成本地系统代码的过程,以提高应用程序的性能和响应速度。在Spring Boot 3.0或Spring Framework 6.0之后,我们可以直接使用Spring Framework 6.0内置的支持来处理AOT。我们可以通过自定义aot.factories文件配置来实现。未来,mica-auto也将支持使用注解来生成aot.factories文件。在Gradle构建工具中,我们可以在build.gradle文件中配置相关插件和依赖项,以支持Spring Boot AOT。例如,我们可以使用org.springframework.boot和io.spring.dependency-management插件,并在dependencies部分添加相应的依赖项。在应用程序代码中,我们需要使用@RestController和@SpringBootApplication注解来标记主类和控制器类。在主方法中,我们使用SpringApplication.run()方法启动应用程序。通过以上配置和代码,我们可以实现Spring Boot AOT。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring Boot 3.0 抢先了解:aot.factories 是个啥?](https://blog.csdn.net/j3T9Z7H/article/details/127437745)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Spring Boot 3AOTGraalVM Native Image应用开发](https://blog.csdn.net/haiyan_qi/article/details/128057967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值