编程语⾔SpringNative实战(畅快体验79毫秒启动springboot应⽤)
欢迎访问我的GitHub
github/zq2599/blog_demos
内容:所有原创⽂章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
关于Spring Native
Spring官⽅博客于2021年03⽉11⽇宣布Spring Native的beta版本发布,借助Spring Native可以将spring应⽤与GraalVM集成到native image中;
native image是GraalVM的⼀项技术,会将java应⽤的字节码编译成可执⾏⽂件,还会与JDK的本地库做静态链接,运⾏应⽤时⽆需Java虚拟机,⾃⾝已集成了内存管理,线程调度等能⼒,更多信息请参考:本⽂以实战为主,因此不会⽤太多篇幅介绍Spring Native的理论和优势,这⾥简单⼩结⼏个重要特性:
1. 应⽤启动速度不超过100毫秒;
2. 启动即达到性能峰值(C1、C2等⼿段已经⽤不上了)
3. 运⾏时更低的内存消耗;
4. docker镜像不含JDK(所需⽂件已经抽取出来放⼊镜像),官⽅展⽰的含有Spring Boot, Spring MVC, Jackson, Tomcat的镜像⼤⼩是50M;
5. 为了达到前⾯的效果,代价是构建时间更长;
Spring Native到底是什么
个⼈的理解:Spring Native是Spring提供的、制作native image的技术⽅案,涉及到以下关键技术:
1. Spring ahead-of-time (AOT) 插件,对spring应⽤做AOT处理,使得传统虚拟机的class lazy loading在不复存在;
2. spring-boot-maven-plugin插件在构建docker镜像的时候,使⽤了名为dmikusa/graalvm-tiny的镜像作为构建⼯具,这个⼯具负责将当前⼯程的构建结果和GraalVM集成在⼀起,最终制作成native image;本篇概览
作为实战风格的⽂章,本篇主要内容是开发springboot应⽤再构建为native image,然后验证其功能和效果,本⽂由以下内容构成:
1. 环境信息
2. 新建名为spring-native-tutorials的maven⽗⼯程,对实战⽤到的依赖库、插件等做统⼀配置;
3. 新建名为webmvc的maven⼦⼯程,这是个springboot应⽤;
4. 将webmvc构建为native image,这是个docker镜像;
5. 在docker中启动镜像,验证是否可⽤,并检查相关相关指标;
环境信息
本次实战相关的环境信息如下:
1. 电脑:MacBook pro 13⼨ 2018
2. 操作系统:macOS Big Sur 11.2.3
3. IDE:IntelliJ IDEA 2018.3.5 (Ultimate Edition)
4. docker:20.10.5
5. JDK:1.8.0_211
6. maven:3.6.0
7. springboot:2.5.0-SNAPSHOT
8. spring-aot-maven-plugin:0.10.0-SNAPSHOT
源码下载
本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所⽰(github/zq2599/blog_demos):
名称链接备注
项⽬主页github/zq2599/blog_demos该项⽬在GitHub上的主页
git仓库地址(https)github/zq2599/blog_demos.git该项⽬源码的仓库地址,https协议
git仓库地址(ssh)git@github:zq2599/blog_demos.git该项⽬源码的仓库地址,ssh协议
这个git项⽬中有多个⽂件夹,本次实战的源码在spring-native-tutorials⽂件夹下,如下图红框所⽰:
新建名为spring-native-tutorials的maven⽗⼯程
对Spring Native的学习不是写出helloworld就完事,因此这⾥先创建⼀个⽗⼯程,为今后所有的应⽤提供统⼀的依赖库、插件管理;
新建名为spring-native-tutorials的maven⽗⼯程,l内容如下,有⼏处要注意的地⽅稍后提到:
<?xml version="1.0" encoding="UTF-8"?>4.0.0webmvcorg.springframework.bootspring-boot-starter-parent2.5.0-SNAPSHOTcom.bolingcavalryspring-native-tutorials1.0-SNAPSHOTpom1.8dmikusa/graalvm-tiny2020.0.2spring-releaseSpring                            ${builder}true${native.build.args}IF_NOT_perimentalspring-aot-maven-plugin0.10.0-SNAPSHOTtest-generatetest-generategenerategenerate 上述l有以下⼏处需要注意:
1. 插件仓库、依赖库仓库、依赖库版本的配置都集中在这⾥;
2. 配置好spring-aot-maven-plugin和spring-boot-maven-plugin这两个插件,⼦⼯程会⽤到;
3. spring-boot-maven-plugin插件制作docker镜像的时候,⼜会⽤到dmikusa/graalvm-tiny镜像,这才是真正构建native image的⼯具;
新建springboot类型的maven⼦⼯程
新建名为webmvc的⼦⼯程,l内容如下,可见内容很简单,就是常规依赖库和⽗⼯程配置的两个插件,⼀个负责执⾏AOT,⼀个负责构建镜像:
<?xml version="1.0" encoding="UTF-8"?>spring-native-tutorialscom.bolingcavalry1.0-SNAPSHOT4.0.perimentalspring-nativeorg.springframework.at.embedtomc
代码很简单,⼀个普通的springboot应⽤,带http接⼝:
package com.bolingcavalry.webmvc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@SpringBootApplication
@RestController
public class WebmvcApplication {
public static void main(String[] args) {
SpringApplication.run(WebmvcApplication.class, args);
}
@ResponseStatus(HttpStatus.ACCEPTED)
@GetMapping("/status")
public String status() {
return "status";
}
@GetMapping("/")
public String hello() {
return "1. Hello from Spring MVC and Tomcat, " + w();
}
}
现在编码已完成,来构建docker镜像吧,进⼊⽗⼯程的l所在⽬录,执⾏以下命令:
mvn clean -U -DskipTests spring-boot:build-image
构建成功后输出信息如下(篇幅所限仅截取最后⼀⼩段),耗时4分25秒,期间笔记本风扇狂转:
.
..
[INFO] Successfully built image 'docker.io/library/webmvc:1.0-SNAPSHOT'
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for spring-native-tutorials 1.0-SNAPSHOT:
[INFO]
[INFO] spring-native-tutorials ............................ SUCCESS [  1.786 s]
[INFO] webmvc ............................................. SUCCESS [04:19 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  04:25 min
[INFO] Finished at: 2021-05-22T16:36:44+08:00
[INFO] ------------------------------------------------------------------------
[WARNING] The requested profile "nexus" could not be activated because it does not exist.
执⾏docker images命令,如下图,可见镜像已经⽣成:
查看镜像构成,可见每个layer都不⼤,共计七⼗多M:
(base) zhaoqindeMBP:~ zhaoqin$ docker history webmvc:1.0-SNAPSHOT
IMAGE          CREATED        CREATED BY  SIZE      COMMENT
b8ff54813ae0  41 years ago                69B41 years ago                452kB41 years ago                2.51MB41 years ago                57.2MB41 years ago                1.4MB41 years ago                268B41 years ago                17.3MB 镜像构建成功,可以验证基本功能了;
验证
执⾏以下命令,创建⼀个临时容器(控制台结束后容器会被清理掉):
docker run --rm -p 8080:8080 webmvc:1.0-SNAPSHOT
控制台输出如下,79毫秒启动完成,真是⼀眨间的功夫:
(base) zhaoqindeMBP:~ zhaoqin$ docker run --rm -p 8080:8080 webmvc:1.0-SNAPSHOT
2021-05-22 09:34:57.578  INFO 1 --- [          main] o.s.nativex.NativeListener              : This application is bootstrapped with code generated with Spring AOT
.  ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
'  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::      (v2.5.0-SNAPSHOT)
2021-05-22 09:34:57.586  INFO 1 --- [          main] c.b.webmvc.WebmvcApplication            : Starting WebmvcApplication using Java 1.8.0_292 on 3529ec458896 with PID 1 (/workspace/com.bolingcavalry.webmvc.WebmvcApplication start 2021-05-22 09:34:57.586  INFO 1 --- [          main] c.b.webmvc.WebmvcApplication            : No active profile set, falling back to default profiles: default
2021-05-22 09:34:57.661  INFO 1 --- [          main] o.s.at.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
May 22, 2021 9:34:57 AM AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
May 22, 2021 9:34:57 AM org.StandardService startInternal
INFO: Starting service [Tomcat]
May 22, 2021 9:34:57 AM org.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/9.0.46]
May 22, 2021 9:34:57 AM org.ApplicationContext log
INFO: Initializing Spring embedded WebApplicationContext
2021-05-22 09:34:57.669  INFO 1 --- [          main] ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 79 ms
May 22, 2021 9:34:57 AM AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
2021-05-22 09:34:57.713  INFO 1 --- [          main] o.s.at.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-05-22 09:34:57.713  INFO 1 --- [          main] c.b.webmvc.WebmvcApplication            : Started WebmvcApplication in 0.178 seconds (JVM running for 0.19)
2021-05-22 09:34:57.713  INFO 1 --- [          main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state LivenessState changed to CORRECT
2021-05-22 09:34:57.714  INFO 1 --- [          main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
浏览器访问本机8080端⼝,如下图,应⽤基本功能正常:
再看看资源使⽤情况,命令是docker stats,如下可见,内存仅⽤了30M:
CONTAINER ID  NAME              CPU %    MEM USAGE / LIMIT    MEM %    NET I/O          BLOCK I/O    PIDS
6ce6c66fb4de  jovial_hertz      0.11%    30.69MiB / 3.844GiB  0.78%    1.49kB / 158B    4.31MB / 0B  18
我曾经在hub.docker上放了⼀个传统springboot应⽤制作的镜像bolingcavalry/hellojib:0.0.1-SNAPSHOT,现在拿来和Spring Native镜像对⽐⼀下,启动信息如下,耗时2036毫秒:
我曾经在hub.docker上放了⼀个传统springboot应⽤制作的镜像bolingcavalry/hellojib:0.0.1-SNAPSHOT,现在拿来和Spring Native镜像对⽐⼀下,启动信息如下,耗时2036毫秒:
(base) zhaoqindeMacBook-Pro:~ zhaoqin$ docker run --rm -P docker.io/bolingcavalry/hellojib:0.0.1-SNAPSHOT
.  ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
'  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::        (v2.1.6.RELEASE)
2021-05-22 11:13:28.121  INFO 1 --- [          main] c.b.hellojib.HellojibApplication        : Starting HellojibApplication on ffb32e5b68b9 with PID 1 (/app/classes started by root in /)
2021-05-22 11:13:28.128  INFO 1 --- [          main] c.b.hellojib.HellojibApplication        : No active profile set, falling back to default profiles: default
2021-05-22 11:13:30.000  INFO 1 --- [          main] o.s.at.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-05-22 11:13:30.054  INFO 1 --- [          main] o.StandardService  : Starting service [Tomcat]
2021-05-22 11:13:30.054  INFO 1 --- [          main] org.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.21]
2021-05-22 11:13:30.241  INFO 1 --- [          main] C.[Tomcat].[localhost].[/]      : Initializing Spring embedded WebApplicationContext
2021-05-22 11:13:30.241  INFO 1 --- [          main] o.t.ContextLoader            : Root WebApplicationContext: initialization completed in 2036 ms
2021-05-22 11:13:30.715  INFO 1 --- [          main] o.urrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-05-22 11:13:31.103  INFO 1 --- [          main] o.s.at.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-05-22 11:13:31.110  INFO 1 --- [          main] c.b.hellojib.HellojibApplication        : Started HellojibApplication in 3.618 seconds (JVM running for 4.297)
2021-05-22 11:13:48.866  INFO 1 --- [nio-8080-exec-1] C.[Tomcat].[localhost].[/]      : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-05-22 11:13:48.866  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-05-22 11:13:48.880  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms
再⽤docker stats对⽐内存,传统springboot应⽤的容器消耗了三百多兆内存:bootstrapped
CONTAINER ID  NAME              CPU %    MEM USAGE / LIMIT    MEM %    NET I/O          BLOCK I/O    PIDS
ffb32e5b68b9  eager_williamson  0.64%    356.3MiB / 3.844GiB  9.05%    3.46kB / 2.29kB  0B / 0B      31
6ce6c66fb4de  jovial_hertz      0.11%    30.69MiB / 3.844GiB  0.78%    1.49kB / 158B    4.31MB / 0B  18
综上所述,Spring Native带来的优势是很明显的,不过请注意:2021年03⽉11⽇官⽅宣布的Spring Native只是beta版本,请不要⽤于⽣产环境!!!
下载插件失败
在实际操作过程中,经常会遇到maven插件或者docker镜像下载失败的情况,除了多试⼏次,您还可以考虑将项⽬放到github上去,借助github action在云端完成镜像构建,具体操作请参考《⽤GitHub Actions制作Do 不⽤开发,直接体验
我已将镜像上传到hub.docker,完整名称是bolingcavalry/webmvc:1.0-SNAPSHOT,如果您只想体验⼀下native image的效果可以直接下载该镜像使⽤;
你不孤单,欣宸原创⼀路相伴
1. Java系列
2. Spring系列
3. Docker系列
4. kubernetes系列
5. 数据库+中间件系列
6. DevOps系列

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。