關注公眾號:鍋外的大佬, 每日推送國外技術好文,幫助每位開發者更好成長

原文鏈接: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
感謝觀看!
