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


    前言
    使用的是 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)
    FluxBaseline
    使用 SpringInitializr 创建项目,仅包含 Reactive Web。接下来,我会写一个 WebMVC 风格的极简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.0.RELEASE。
    <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
    现在,以这个结果作为基线。让我们从这里开始。
    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 快了一点,难道不是吗?
    spring-context-indexer
    接下来,我试了 spring-context-indexer,似乎创建了 component index。
    <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
    惰性初始化
    尝试了惰性初始化。
    @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
    NoVerify
    运行加 -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
    启动变得快了一点。不知道为什么有这个结果,稍后需要仔细了解一下。
    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
    嗯,快多了!减少了几乎2秒。还是不知道这个参数有什么含义,稍后需要仔细了解一下。
    指定 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
    嗯,又变慢了。
    关闭 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
    变得快了一点。
    取消 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
    嗯…似乎有一点点改进?
    取消 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
    结果变快了一点。
    取消 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
    也有一点效果。
    到这里为止,不再取消函数库了。
    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的相关文章,找到原因了。
    SpringBoot FatJAR 不在 CDS 管理范围内。
    使用 Thin Launcher 的 Flux
    嗯,对不起,“Exploded” 基准测试错了。我曾经试着使用 FatJAR,但是 CDS 不能这么干。所以,我转而使用 Thin Launcher,所以 “Exploded” 就变成了 “Thin Launche”。
    使用 CDS 以前,我会测试使用 Thin Launcher 打包 JAR 文件的启动速度。
    <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 class 让启动尽可能快一些。
    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
    嗯,快了一点,对吗?
    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
    喔!变得更快了!
    所有操作都上
    最终,我把所有操作都用上。
    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秒钟!(∩´∀`)∩耶
    更进一步
    在 Dave 的视频中,他提到了“函数式 Bean 定义”,尝试仅使用 Spring 不用 SpringBoot,app变得更快了。其中的道理还需要进一步了解。
    结果:
    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
    真的很有意思。感谢!
     
    最后
    欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持
  • 相关阅读:
    与众不同 windows phone (50)
    与众不同 windows phone (49)
    重新想象 Windows 8.1 Store Apps (93)
    重新想象 Windows 8.1 Store Apps 系列文章索引
    重新想象 Windows 8.1 Store Apps (92)
    重新想象 Windows 8.1 Store Apps (91)
    重新想象 Windows 8.1 Store Apps (90)
    重新想象 Windows 8.1 Store Apps (89)
    重新想象 Windows 8.1 Store Apps (88)
    重新想象 Windows 8.1 Store Apps (87)
  • 原文地址:https://www.cnblogs.com/zhuifeng523/p/11511605.html
Copyright © 2020-2023  润新知