关注公众号:锅外的大佬, 每日推送国外技术好文,帮助每位开发者更好成长
原文链接: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
感谢观看!