AOT 提前编译 Ahead-of-Time .NET9+、JDK24起支持AOT、Quarkus(GraalVM)
综合/最新
编程
主要
- 通用
JDK24 支持了部分 GC 环境的AOT,自 JDK26 起支持了包含 ZGC 在内的所有 GC;JDK25起AOT记录和创建流程合并为单步 java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...。
Java
- GraalVM
Oracle GraalVM 只是拿不到下新补丁,主版本免费用;而 GraalVM Community Edition (CE) 缺失 G1 垃圾回收的支持,只用于洁癖者使用。 Substrate VM(svm.jar/5MiB)相比 HotSpot VM,精简掉了JIT 等运行时组件,内存占用从约 100MB 减少为不到 10MB。 原理:将jar包和classes转译为二进制程序,但Resource文件则需要显式包含进来,且不会自动包含jar包内资源。访问资源用 Thread.currentThread().getContextClassLoader().getResourceAsStream(); Jetty库Graal配置 - https://github.com/oracle/graalvm-reachability-metadata/tree/master/metadata/org.eclipse.jetty/jetty-server 插件用法: plugins { application // ./gradlew nativeCompile 会识别 application.mainClass 作为程序入口 // 输出目录 ls graalvm-app/build/native/nativeCompile/[项目名/Windows则含后缀.exe] // 部分依赖库(Jetty等)还会生成 libmanagement_ext.so 库,应跟主程序(约17MB)放同目录下待用。 // 执行(亲测GCE对其SSE完美支持) chmod 777 graalvm-app & ./graalvm-app id("org.graalvm.buildtools.native") version "1.1.2" } graalvmNative { // 已存在 GRAALVM_HOME 应关闭探测;不支持变种 Mandrel。 toolchainDetection.set(true) // 自动匹配官方维护的反射元数据配置 //metadataRepository { enabled.set(false) } // src/main/resources/META-INF/native-image/主程序不重名即可/但必须两层目录/reflect-config.json 若存在全格式的 reachability-metadata.json 则忽略其他 *.json。 binaries { named("main") { verbose.set(true) fallback.set(false) // 等同 --no-fallback //buildArgs.add("-march=native") // 充分利用 CPU SIMD 等特性;或兼容旧处理器 compatibility } } agent { metadataCopy { inputTaskNames.add("run") // ./gradlew metadataCopy --task run、--task test outputDirectories.add("src/main/resources/META-INF/native-image/my-main-website/censored-web/") // or --dir mydir/ mergeWithExisting.set(true) } } } dependencies { // 该插件似乎依赖以下俩库,否则报警告。 implementation("com.google.guava:guava:33.6.0-jre") testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.1.0") //implementation(platform("org.eclipse.jetty:jetty-bom:12.1.10")) // 注释避开 listLibrariesMissingMetadata 任务扫描;合并配置路径 - graalvm-app\build\reports\native\list-libraries-missing-metadata.json } 注解声明可达性: // compileOnly("org.graalvm.sdk:nativeimage:25.0.3") // ImageInfo.inImageCode() 找不到类可换为 System.getProperty("org.graalvm.nativeimage.imagecode") 返回 buildtime、runtime、agent // 注解扫描太耗时(已废弃),故显式将 Args = --features=pkg.NativeFeature 写入 src\main\resources\META-INF\native-image\my-main-website\censored-web\native-image.properties public class NativeFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { System.out.println("NativeFeature beforeAnalysis..."); RuntimeReflection.register(String.class); } } 容器中运行: 首选包含 C/C++ 运行环境的基础镜像进行构建(免登陆) gcr.io/distroless/cc 只有纯 Go 程序(自带DNS方案)才使用 distroless/static 或包含了 glibc 但无 libstdc++.so 的 gcr.io/distroless/base- Quarkus
首选 quarkus-resteasy,若未用到 Jakarta StreamingOutput 则可换用 reactive 的 quarkus-rest。 quarkus-rest 中需要用 Mutiny 库的 Multi<byte[]> 来替代 StreamingOutput;其 Uni 类型名的含义为单一性前缀。 quarkus-rest-client 兼容 quarkus-rest 和 quarkus-resteasy 服务端,JVM跑不了其依赖的ArC库CDI环境,已取代 quarkus-resteasy-client。 @RegisterRestClient(baseUri = "https://domain.name/apis") 方式或 QuarkusRestClientBuilder.newBuilder().baseUri(URI.create("https://domain.name/api")).build(ClientInterface.class); 资源: 自动包含该目录下资源 src\main\resources\META-INF\resources\ 需显式包含资源根目录 src\main\resources\ 读取资源文件亲测可用: Thread.currentThread().getContextClassLoader().getResourceAsStream("x.txt"); StreamUtil.class.getResourceAsStream("/x.txt"); HTTP/HTTPS: environment variable QUARKUS_HTTP_SSL_CERTIFICATE_KEY_STORE_PASSWORD. quarkus.http.port=8080 # 关闭80端口访问: quarkus.http.insecure-requests=disabled quarkus.http.ssl-port=8443 quarkus.http.ssl.certificate.key-store-file=/path/to/keystore 非quarkus环境Rest Client: implementation("org.jboss.weld.se:weld-se-core:6.0.3.Final") implementation("io.smallrye:jandex:3.4.0") // for weld implementation("org.jboss.resteasy.microprofile:microprofile-rest-client:3.0.1.Final") implementation("io.smallrye.config:smallrye-config:3.13.4") // for resteasy implementation("io.quarkus:quarkus-undertow") // Servlet @Path("meta") @RegisterRestClient(baseUri = "https://congci.com/main/apis/core") public interface DefaultRestClient { @GET // https://congci.com/main/apis/core/meta/servlet-info @Path("/servlet-info") @Produces(MediaType.TEXT_PLAIN) public String servletInfo(); } CDI.current().select(DefaultRestClient.class).get(); 最简实例: dependencies { implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")) implementation("io.quarkus:quarkus-arc") // Build-Time CDI implementation("io.quarkus:quarkus-rest") // Vert.x 反应式 JAX-RS or 换为传统的 quarkus-resteasy } Restful: Quarkus 支持 class/record 自定义实体写成内部类,但必须注解@RegisterForReflection,且 class 必须存在无参构造器: @RegisterForReflection public record ResultRecord(String text) { } Response.ok(new ResultRecord(r)).header("X-Robots-Tag", "noindex").build(); Quarkus 不支持 @FormParam("key") 接参,需换用 MultipartFormDataInput - input.getFormDataMap().get("k").getFirst().getBodyAsString();
其他
使 houbb:segment 分词库支持 Quarkus 原生构建、使 houbb:opencc4j 中文简繁转换库支持 Quarkus 原生构建