关注公众号:锅外的大佬, 每日推送国外技术好文,帮助每位开发者更好成长

原文链接:https://dev.to/bufferings/lets-make-springboot-app-start-faster-k9m

作者:Mitz

译者:Lensen

"Spring有多快?" 这是2018年”Spring One Platfrom“大会的一个主题,我看了视频并亲自尝试了一下。所以我将在这篇文章中,介绍下我所做的事情以及结果。

没看过的推荐去看一下,蛮有意思的:
https://springoneplatform.io/2018/sessions/how-fast-is-spring-
源代码地址:https://github.com/bufferings/spring-boot-startup-mybench

我使用OpenJDK 11:

❯ java --version
openjdk 11.0.1 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

你可以像下面一样运行基准测试,这需要点时间,因为会执行所有基准测试。

❯ ./mvnw clean package
❯ (cd benchmarks/; java -jar target/benchmarks.jar)

1.Flux Baseline

我用SpringInitializer创建一个只有Reactive Web的项目,然后用SpringMVC风格创建了一个Controller

@SpringBootApplication
@RestController
public class DemoApplication { @GetMapping("/")
public String home() {
return "Hello";
} public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

Spring Boot版本是2.1.0RELEASE.

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

启动时间为2.938±0.287 s/op。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op

现在我得到一个对比启动时间的基线(baseline),让我们从这里开始。

2.WebMVC

我想知道WebMVC怎么样,而不是WebFlux。也许这仅仅意味着Tomcat和Netty之间的比较呢?

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case02_Web ss 10 3.281 ± 0.342 s/op

WebFlux更快点,对吧?

3.spring-context-indexer

接下来,我尝试了spring-context-indexer,它似乎创建了主键索引

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<optional>true</optional>
</dependency>

呃...变慢了一点?

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case03_WithContextIndexer ss 10 3.063 ± 0.102 s/op

我检查了spring.components,发现它只包含一个组件。我明白了…我应该尝试一个更大的项目来了解效果。

#
#Sun Nov 04 18:42:59 JST 2018
com.example.DemoApplication=org.springframework.stereotype.Component

4.Lazy Initialization

尝试懒初始化

@Configuration
public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
beanFactory.getBeanDefinition(beanName).setLazyInit(true);
}
}

结果如下,它只变快了一点儿。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case04_WithLazyInit ss 10 2.844 ± 0.129 s/op

5.No Verify

启动时使用-noverify,不进行验证:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case05_WithNoVerifyOption ss 10 2.582 ± 0.060 s/op

它变快了一点。我不知道这是什么意思,所以之后要查一下。

6.TieredStopAtLevel

启动时使用-XX:TieredStopAtLevel=1

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case06_WithTieredStopAtLevel1Option ss 10 1.980 ± 0.037 s/op

Uh!快了很多,启动时间接近两秒,但我还是不清楚为什么,稍后我会去查一下。

7.显式指定SpringConfigLocation

启动时使用Dspring.config.location=classpath:/application.properties:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case07_WithSpringConfigLocationOption ss 10 3.026 ± 0.139 s/op

它变慢了...

8.关闭JMX

启动时使用-Dspring.jmx.enabled=false:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case08_WithJmxDisabledOption ss 10 2.877 ± 0.097 s/op

它变得快了些。

9.排除Logback

到这,我尝试排除些依赖。首先,排除Logback

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
</dependency>

结果如下:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case09_WithoutLogback ss 10 2.904 ± 0.096 s/op

好像稍微有点改进?

10.排除JackSon

下一个是JackSon:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-json</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>

看结果:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case10_WithoutJackson ss 10 2.789 ± 0.093 s/op

变快了一点儿。

11.排除 HibernateValidator

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<exclusions>
<exclusion>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</exclusion>
</exclusions>
</dependency>

结果:

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case11_WithoutHibernateValidator ss 10 2.857 ± 0.084 s/op

也有一点改进。
排除依赖库到这就结束了。

12.AppCDS

AppCDS(应用程序类数据共享,Application Class Data Sharing)作为一个商业特性包含在Oracle JDK中。但它在OpenJDK 10中可用。

AppCDS似乎将信息转储到共享存档中,因此启动时间变得更短。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case12_WithAppCds ss 10 2.957 ± 0.079 s/op

它没有变得更快,然后我查找了CDS的相关资料发现:使用Spring Boot FatJAR时,这些库不在CDS的范围内。

13.Flux with Thin Launcher

抱歉,基准命名为‘Exploded’是不对的,一次我尝试暴露FatJar,但我仍然不能使用CDS。所以我现在使用Thin Launcher,所以请把基准名称从Exploded改为Thin Launcher吧。

在使用CDS之前,我想检查下使用Thin Launcher打包的速度。

 <plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-layout</artifactId>
<version>1.0.15.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>

虽然我使用Thin Launcher来打包app,但是我没有使用Thin Launcher的启动类,而是指定了Main类来让启动时间尽可能快些。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case13_Exploded ss 10 2.476 ± 0.091 s/op

变快了点,对吧?

14.Thin Launcher + CDS

现在我要对它使用AppCDS了。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case14_ExplodedWithAppCds ss 10 1.535 ± 0.036 s/op

Wow! 它变快了很多!

15.全部应用

最后,我把上面所有方法的都应用在程序上。

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case15_AllApplied ss 10 0.801 ± 0.037 s/op

启动速度少于1秒钟!yeah!

16.还有一点

在Dave的会议上,他提到了“函数Bean定义”(Functional Bean Definitions),尝试在没有SpringBoot的情况下使用Spring进行改进,应用程序变得更快了。我需要学习更多来理解他们。

17.结果列表

Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline ss 10 2.938 ± 0.287 s/op
MyBenchmark.case02_Web ss 10 3.281 ± 0.342 s/op
MyBenchmark.case03_WithContextIndexer ss 10 3.063 ± 0.102 s/op
MyBenchmark.case04_WithLazyInit ss 10 2.844 ± 0.129 s/op
MyBenchmark.case05_WithNoVerifyOption ss 10 2.582 ± 0.060 s/op
MyBenchmark.case06_WithTieredStopAtLevel1Option ss 10 1.980 ± 0.037 s/op
MyBenchmark.case07_WithSpringConfigLocationOption ss 10 3.026 ± 0.139 s/op
MyBenchmark.case08_WithJmxDisabledOption ss 10 2.877 ± 0.097 s/op
MyBenchmark.case09_WithoutLogback ss 10 2.904 ± 0.096 s/op
MyBenchmark.case10_WithoutJackson ss 10 2.789 ± 0.093 s/op
MyBenchmark.case11_WithoutHibernateValidator ss 10 2.857 ± 0.084 s/op
MyBenchmark.case12_WithAppCds ss 10 2.957 ± 0.079 s/op
MyBenchmark.case13_Exploded ss 10 2.476 ± 0.091 s/op
MyBenchmark.case14_ExplodedWithAppCds ss 10 1.535 ± 0.036 s/op
MyBenchmark.case15_AllApplied ss 10 0.801 ± 0.037 s/op

感谢观看!

让Spring Boot启动更快的更多相关文章

  1. 11个点让你的Spring Boot启动更快

    前言 使用的是 OpenJDK 11. java --version openjdk 11.0.1 2018-10-16 OpenJDK Runtime Environment 18.9 (build ...

  2. Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动

    之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat. private void cr ...

  3. Spring Boot启动过程及回调接口汇总

    Spring Boot启动过程及回调接口汇总 链接: https://www.itcodemonkey.com/article/1431.html 来自:chanjarster (Daniel Qia ...

  4. 82. Spring Boot – 启动彩蛋【从零开始学Spring Boot】

    我们在[28. SpringBoot启动时的Banner设置 ] 这一小节介绍过设置Spring Boot的Banner,但是实际当中,我们希望做的更漂亮,所以也就有了这小节Spring Boot-启 ...

  5. Spring Boot启动命令参数详解及源码分析

    使用过Spring Boot,我们都知道通过java -jar可以快速启动Spring Boot项目.同时,也可以通过在执行jar -jar时传递参数来进行配置.本文带大家系统的了解一下Spring ...

  6. Spring Boot启动流程分析

    引言 早在15年的时候就开始用spring boot进行开发了,然而一直就只是用用,并没有深入去了解spring boot是以什么原理怎样工作的,说来也惭愧.今天让我们从spring boot启动开始 ...

  7. Spring Boot -- 启动彩蛋

    使用Spring Boot启动的jar包总是会显示一个Spring的图标: . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\_ ...

  8. Spring Boot 启动原理分析

    https://yq.aliyun.com/articles/6056 转 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启 ...

  9. Spring Boot启动过程(七):Connector初始化

    Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...

随机推荐

  1. Java设计模式学习二

    Java设计思想之单例模式 单例模式(Singleton Pattern)是Java中最常见的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的 ...

  2. win10 设置软件开机启动项失效

    问题重现: win10系统,只要是图标右下角带盾牌标志的软件,加入系统的启动文件夹:如:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Sta ...

  3. python 列表 字符串 转换

    列表转字符串python中的列表l = ['1','2','3','4']转成str型'1,2,3,4'','.join(l)这个方法,列表里都是字符串的话可以这样用.列表里是整数的情况可以用: &g ...

  4. 【Luogu】P1593因子和(唯一分解定理,约数和公式)

    题目链接 首先介绍两个定理. 整数唯一分解定理:任意正整数都有且只有一种方式写出素数因子的乘积表达式. \(A=(p1k1 p2k2 ...... pnkn \) 求这些因子的代码如下 ;i*i< ...

  5. 【loj6191】「美团 CodeM 复赛」配对游戏

    题目 显然期望dp. 简单想法: f[i][j]表示前i个人中向右看并且没有被消除的人数的概率 如果第i+1个人是向右,$f[i+1][j+1]=f[i][j]/2$ 如果第i+1个人是向左,$f[i ...

  6. uva 550 有趣的乘法(dfs)

    题目大意:给三个数A(进制).B(如*****7的最后一个数字7).C(*****7*4的后面的因数4)求符合条件下的第一个因数的位数最少 例子: 179487 * 4 = 717948 (10进制) ...

  7. 连通 OR 不连通(NOJ 1044)

    比赛描述 给定一个无向图,一共n个点,请编写一个程序实现两种操作: D x y 从原图中删除连接x,y节点的边. Q x y 询问x,y节点是否连通 输入 第一行两个数n,m(5<=n<= ...

  8. 棋盘制作 BZOJ 1057

    棋盘制作 [问题描述] 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴 ...

  9. Dreamweaver8中文版视频教程 [爱闪教程]Dreamweaver8中文版

    原文发布时间为:2008-07-30 -- 来源于本人的百度文章 [由搬家工具导入] http://www.176net.com/shipin/UploadFiles_1476/teach1/%5B% ...

  10. MySQL导出数据库、数据库表结构、存储过程及函数【用】

    一.导出数据库 我的mysql安装目录是D:\Program Files\MySQL\MySQL Server 5.5\bin\,导出文件预计放在D:\sql\ 在mysql的安装目录执行命令: my ...