zoukankan      html  css  js  c++  java
  • 让Spring Boot启动更快

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

    原文链接: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
    

    感谢观看!

  • 相关阅读:
    openssl对数组加密解密的完整实现代码
    OpenSSl 加密解密 示例(终于有编程实践了)
    QT中QProcess调用命令行的痛苦经历(调用Winrar,设置工作目录,获得输出,注意引号与括号,等等)
    Ubuntu 14.04远程登录服务器--openssh的安装和配置简明步骤
    可复用的批量文件修改工具
    TFS二次开发、C#知识点、SQL知识
    Backbone.js的技巧和模式
    Hibernate:如何映射聚合?
    JavaScript之创建对象
    为什么选择MongoDB?
  • 原文地址:https://www.cnblogs.com/liululee/p/10916028.html
Copyright © 2011-2022 走看看