Spring Native项目实战(体验79毫秒启动springboot应用)

网友投稿 211 2023-01-12

Spring Native项目实战(体验79毫秒启动springboot应用)

欢迎访问我的github

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

关于Spring Native

Spring官方博客于2021年03月11日宣布Spring Native的beta版本发布,借助Spring Native可以将spring应用与GraalVM集成到native image中;

native image是GraalVM的一项技术,会将java应用的字节码编译成可执行文件,还会与JDK的本地库做静态链接,运行应用时无需Java虚拟机,自身已集成了内存管理,线程调度等能力,更多信息请参考:https://graalvm.org/reference-manual/native-image/

本文以实战为主,因此不会用太多篇幅介绍Spring Native的理论和优势,这里简单小结几个重要特性:

应用启动速度不超过100毫秒;

启动即达到性能峰值(C1、C2等手段已经用不上了)

运行时更低的内存消耗;

docker镜像不含JDK(所需文件已经抽取出来放入镜像),官方展示的含有Spring Boot, Spring MVC, Jackson, Tomcat的镜像大小是50M;

为了达到前面的效果,代价是构建时间更长;

Spring Native到底是什么

个人的理解:Spring Native是Spring提供的、制作native image的技术方案,涉及到以下关键技术:

Spring ahead-of-time (AOT) 插件,对spring应用做AOT处理,使得传统虚拟机的class lazy loading在不复存在;

spring-boot-maven-plugin插件在构建docker镜像的时候,使用了名为dmikusa/graalvm-tiny的镜像作为构建工具,这个工具负责将当前工程的构建结果和GraalVM集成在一起,最终制作成native image;

本篇概览

作为实战风格的文章,本篇主要内容是开发springboot应用再构建为native image,然后验证其功能和效果,本文由以下内容构成:

环境信息

新建名为spring-native-tutorials的maven父工程,对实战用到的依赖库、插件等做统一配置;

新建名为webmvc的maven子工程,这是个springboot应用;

将webmvc构建为native image,这是个docker镜像;

在docker中启动镜像,验证是否可用,并检查相关相关指标;

环境信息

本次实战相关的环境信息如下:

电脑:MacBook pro 13寸 2018

操作系统:macOS Big Sur 11.2.3

IDE:IntelliJ IDEA 2018.3.5 (Ultimate Edition)

docker:20.10.5

JDK:1.8.0_211

maven:3.6.0

springboot:2.5.0-SNAPSHOT

spring-aot-maven-plugin:0.10.0-SNAPSHOT

源码下载 本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):

名称

链接

备注

项目主页

https://github.com/zq2599/blog_demos

该项目在GitHub上的主页

git仓库地址(https)

https://github.com/zq2599/blog_demos.git

该项目源码的仓库地址,https协议

git仓库地址(ssh)

git@github.com:zq2599/blog_demos.git

该项目源码的仓库地址,ssh协议

这个git项目中有多个文件夹,本次实战的源码在spring-native-tutorials文件夹下,如下图红框所示:

新建名为spring-native-tutorials的maven父工程

对Spring Native的学习不是写出helloworld就完事,因此这里先创建一个父工程,为今后所有的应用提供统一的依赖库、插件管理;

新建名为spring-native-tutorials的maven父工程,pom.xml内容如下,有几处要注意的地方稍后提到:

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

webmvc

org.springframework.boot

spring-boot-starter-parent

2.5.0-SNAPSHOT

com.bolingcavalry

spring-native-tutorials

1.0-SNAPSHOT

pom

1.8

dmikusa/graalvm-tiny

2020.0.2

spring-release

Spring release

https://repo.spring.io/release

false

spring-milestone

Spring milestone

https://repo.spring.io/milestone

false

spring-snapshot

Spring Snapshots

https://repo.spring.io/snapshot

false

spring-release

Spring release

https://repo.spring.io/release

false

spring-milestone

Spring milestone

https://repo.spring.io/milestone

false

spring-snapshot

Spring Snapshots

https://repo.spring.io/snapshot

false

org.springframework.experimental

spring-native

0.10.0-SNAPSHOT

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

org.springframework.boot

spring-boot-maven-plugin

${classifier}

${builder}

true

${native.build.args}

IF_NOT_PRESENT

org.springframework.experimental

spring-aot-maven-plugin

0.10.0-SNAPSHOT

test-generate

test-generate

generate

generate

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

webmvc

org.springframework.boot

spring-boot-starter-parent

2.5.0-SNAPSHOT

com.bolingcavalry

spring-native-tutorials

1.0-SNAPSHOT

pom

1.8

dmikusa/graalvm-tiny

2020.0.2

spring-release

Spring release

https://repo.spring.io/release

false

spring-milestone

Spring milestone

https://repo.spring.io/milestone

false

spring-snapshot

Spring Snapshots

https://repo.spring.io/snapshot

false

spring-release

Spring release

https://repo.spring.io/release

false

spring-milestone

Spring milestone

https://repo.spring.io/milestone

false

spring-snapshot

Spring Snapshots

https://repo.spring.io/snapshot

false

org.springframework.experimental

spring-native

0.10.0-SNAPSHOT

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

org.springframework.boot

spring-boot-maven-plugin

${classifier}

${builder}

true

${native.build.args}

IF_NOT_PRESENT

org.springframework.experimental

spring-aot-maven-plugin

0.10.0-SNAPSHOT

test-generate

test-generate

generate

generate

上述pom.xml有以下几处需要注意:

插件仓库、依赖库仓库、依赖库版本的配置都集中在这里;

配置好spring-aot-maven-plugin和spring-boot-maven-plugin这两个插件,子工程会用到;

spring-boot-maven-plugin插件制作docker镜像的时候,又会用到dmikusa/graalvm-tiny镜像,这才是真正构建native image的工具;

新建springboot类型的maven子工程

新建名为webmvc的子工程,pom.xml内容如下,可见内容很简单,就是常规依赖库和父工程配置的两个插件,一个负责执行AOT,一个负责构建镜像:

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://mavenjdhtk.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

spring-native-tutorials

com.bolingcavalry

1.0-SNAPSHOT

4.0.0

webmvc

org.springframework.experimental

spring-native

org.springframework.boot

spring-boot-starter-web

org.apache.tomcat.embed

tomcat-embed-core

org.apache.tomcat.embed

tomcat-embed-websocket

org.apache.tomcat.experimental

tomcat-embed-programmatic

${tomcat.version}

org.springframework.boot

spring-boot-starter-test

test

org.springframework.experimental

spring-aot-maven-plugin

true

org.springframework.boot

spring-boot-maven-plugin

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://mavenjdhtk.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

spring-native-tutorials

com.bolingcavalry

1.0-SNAPSHOT

4.0.0

webmvc

org.springframework.experimental

spring-native

org.springframework.boot

spring-boot-starter-web

org.apache.tomcat.embed

tomcat-embed-core

org.apache.tomcat.embed

tomcat-embed-websocket

org.apache.tomcat.experimental

tomcat-embed-programmatic

${tomcat.version}

org.springframework.boot

spring-boot-starter-test

test

org.springframework.experimental

spring-aot-maven-plugin

true

org.springframework.boot

spring-boot-maven-plugin

代码很简单,一个普通的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, " + LocalDateTime.now();

}

}

现在编码已完成,来构建docker镜像吧,进入父工程的pom.xml所在目录,执行以下命令:

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 69B

41 years ago 452kB

41 years ago 2.51MB

41 years ago 57.2MB

41 years ago 1.4MB

41 years ago 268B

41 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 started by cnb in /workspace)

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.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)

May 22, 2021 9:34:57 AM org.apache.coyote.AbstractProtocol init

INFO: Initializing ProtocolHandler ["http-nio-8080"]

May 22, 2021 9:34:57 AM org.apache.catalina.core.StandardService startInternal

INFO: Starting service [Tomcat]

May 22, 2021 9:34:57 AM org.apache.catalina.core.StandardEngine startInternal

INFO: Starting Servlet engine: [Apache Tomcat/9.0.46]

May 22, 2021 9:34:57 AM org.apache.catalina.core.ApplicationContext log

INFO: Initializing Spring embedded WebApplicationContext

2021-05-22 09:34:57.669 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 79 ms

May 22, 2021 9:34:57 AM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler ["http-nio-8080"]

2021-05-22 09:34:57.713 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.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

http://

浏览器访问本机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.com上放了一个传统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.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)

2021-05-22 11:13:30.054 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]

2021-05-22 11:13:30.054 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.21]

2021-05-22 11:13:30.241 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext

2021-05-22 11:13:30.241 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2036 ms

2021-05-22 11:13:30.715 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'

2021-05-22 11:13:31.103 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.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] o.a.c.c.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应用的容器消耗了三百多兆内存:

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制作Docker镜像》

不用开发,直接体验

我已将镜像上传到hub.docker.com,完整名称是bolingcavalry/webmvc:1.0-SNAPSHOT,如果您只想体验一下native image的效果可以直接下载该镜像使用;

以上就是Spring Native实战(畅快体验79毫秒启动springboot应用)的详细内容,更多关于Spring Native实战的资料请关注我们其它相关文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:福建国内快递物流查询单号(闽南快递单号查询)
下一篇:Java 二叉树遍历的常用方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~