/Library/Java/JavaVirtualMachines/
export GRAALVM17_HOME=$(/usr/libexec/java_home -v 17)
export JAVA_HOME=$GRAALVM17_HOME
alias java17g='export JAVA_HOME=$GRAALVM17_HOME;java -version'
$ sudo xattr -r -d com.apple.quarantine $GRAALVM17_HOME
$ java -version
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 17.0.1+12-jvmci-21.3-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 17.0.1+12-jvmci-21.3-b05, mixed mode, sharing)
$ cd $GRAALVM_HOME/bin
$ ./gu install native-image
$ sudo xcode-select --install
.
├── HELP.md
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── ajk
│ │ │ └── testspringnative
│ │ │ └── TestSpringNativeApplication.java
│ │ └── resources
│ │ ├── application.yml
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── com
│ └── ajk
│ └── testspringnative
│ └── TestSpringNativeApplicationTests.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class TestSpringNativeApplication {
public static void main(String[] args) {
SpringApplication.run(TestSpringNativeApplication.class, args);
}
@GetMapping("/hello")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
server:
port: 9000
shutdown: graceful
spring:
profiles:
active: default
logging:
level:
root: info
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ajk</groupId>
<artifactId>test-spring-native</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-spring-native</name>
<description>test-spring-native</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
-
用Spring Boot Buildpacks生成包含原生应用的OCI容器。
-
用GraalVM native image Maven plugin生成原生应用。
<repositories>
<!-- ... -->
<repository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<pluginRepositories>
<!-- ... -->
<pluginRepository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.11.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.11.1</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.9</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<!-- ... -->
</configuration>
</plugin>
<!-- Avoid a clash between Spring Boot repackaging and native-maven-plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
$ mvn clean -Pnative -DskipTests package
-
fatjar包文件为17.8M(不包含JRE),原生可执行文件为68.2M。
-
使用spring-boot-maven-plugin生成包含JRE运行环境的容器镜像大小为270M,而使用Tiny Core Linux+原生应用的形式,镜像大小可以控制在100M以内,为96M。压缩比达到35%之多。
-
fatjar启动时间为8.2s
-
原生文件启动时间为5.6s
-
fatjar空载CPU 0.5%,内存使用528M
-
原生应用空载CPU 0.3%,内存使用85M
FatJar包 | Native包 | |
应用大小 | 17.8M | 68.2M |
容器镜像大小 | 270M | 96M |
启动速度 | 8.2s | 5.6s |
空载CPU | 0.5% | 0.3% |
空载内存 | 528M | 85M |
-
https://github.com/graalvm/graalvm-ce-builds/releases
-
https://github.com/huang-kai/test-spring-native
-
https://www.graalvm.org/docs/introduction/
-
https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/
-
https://openjdk.java.net/jeps/243
-
http://trufflesuite.com/truffle/
-
https://github.com/graalvm/labs-openjdk-17
原文始发于微信公众号(分布式实验室):Spring Native初探
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论