Project Icon

spring-startup-analyzer

Spring应用启动性能分析与优化工具

Spring Startup Analyzer是一个开源的Spring应用启动分析工具,能够生成详细的交互式启动报告。该工具提供Bean初始化详情、时间线、方法调用统计等多维度数据分析,以及未使用Jar包的识别,帮助开发者定位启动性能瓶颈。此外,它还支持Bean异步初始化,为优化Spring应用的启动速度提供了全面解决方案。

license maven Coverage GitHub all releases download

英文 | 中文

Spring启动分析器

Spring启动分析器生成一个交互式的Spring应用启动报告,让你了解哪些因素影响了应用的启动时间,并帮助优化它。用户界面参考了spring-boot-startup-report

分析报告演示

🤩亮点

📈Spring启动分析报告

Spring Bean初始化详情支持初始化时间/bean名称搜索,Spring Bean初始化时间线方法调用次数和时间统计(支持自定义方法),未使用的Jar包(帮助优化fat jar),以及应用启动线程墙钟分析,帮助开发人员快速分析和定位应用启动瓶颈。支持linux/mac/windows系统。

  • Spring Bean初始化详情 Spring Bean初始化

  • Spring Bean初始化时间线 Spring Bean时间线

  • 方法调用次数和时间统计 方法调用详情

  • 未使用的Jar包 未使用的Jar包

  • 应用启动线程墙钟分析 火焰图

🚀Spring启动优化

提供Spring Bean异步初始化jar包,对初始化时间较长的bean异步执行init@PostConstruct方法,以提高应用启动速度。

🧭如何使用

📈Spring启动数据收集

安装

提供两种安装方式:手动安装一键脚本安装

1. 手动安装

  1. 点击realease下载最新版本的tar.gz包

  2. 创建新文件夹并解压文件

对于Linux/Mac系统,可以考虑使用以下命令:

mkdir -p ${HOME}/spring-startup-analyzer
cd 下载路径
tar -zxvf spring-startup-analyzer.tar.gz -C 你的安装路径/spring-startup-analyzer

2. Shell脚本安装(仅适用于Linux/Mac)

curl -sS https://raw.githubusercontent.com/linyimin0812/spring-startup-analyzer/main/bin/install.sh | sh

默认安装目录:$HOME/spring-startup-analyzer

配置

本项目提供几个配置选项,这些配置不是必须的,可以使用默认设置。

有两种配置方式:

  1. 直接在配置文件中配置:你的安装路径/spring-startup-analyzer/config/spring-startup-analyzer.properties
  2. 通过启动参数配置,例如,设置应用启动健康检查超时时间为30分钟:-Dspring-startup-analyzer.app.health.check.timeout=30

确定应用启动成功的标准如下:

  1. SpringApplication.run方法进行字节码增强,方法退出时认为应用启动完成(仅适用于Spring Boot应用)。
  2. 轮询健康检查请求URL,收到200响应时认为启动完成(适用于所有Spring应用)。
  3. 如果上述两种方法都不成功,超过应用启动健康检查超时时间后认为应用启动完成。

对于非Spring Boot应用,需要使用spring-startup-analyzer.app.health.check.endpoints配置健康检查URL。

配置选项描述默认值
spring-startup-analyzer.app.health.check.timeout应用启动检查超时时间(分钟)20
spring-startup-analyzer.app.health.check.endpoints应用启动成功检查URL,可配置多个URL,用逗号分隔http://127.0.0.1:7002/actuator/health
spring-startup-analyzer.admin.http.server.port管理端口8065
spring-startup-analyzer.async.profiler.sample.thread.namesAsync Profiler收集的线程名称,支持多个配置,用逗号分隔main
spring-startup-analyzer.async.profiler.interval.millisasync profiler采样间隔(毫秒)5
spring-startup-analyzer.linux.and.mac.profiler指定linux/mac火焰图分析器:async_profiler/jvm_profilerjvm_profiler
spring-startup-analyzer.log.path日志路径
- startup.log: 启动日志
- transform.log: 类重转换日志
$HOME/spring-startup-analyzer/logs

应用启动

本项目作为agent启动,因此您可以在启动命令中添加参数-javaagent:你的安装路径/spring-startup-analyzer/lib/spring-profiler-agent.jar

  • 如果使用Java命令行启动应用,您需要在命令行中添加参数,例如:
java -javaagent:/Users/runner/spring-startup-analyzer/lib/spring-profiler-agent.jar \
    -Dproject.name=mac-demo \
    -Dspring-startup-analyzer.admin.http.server.port=8066 \
    -jar /Users/runner/spring-startup-analyzer/spring-boot-demo.jar
  • 如果要在IDEA中启动,您需要在VM选项中添加以下内容:

应用启动完成后,控制台和startup.log文件中会打印======= spring-startup-analyzer finished, click http://localhost:xxxx to visit details. ======消息。您可以通过这个输出判断分析是否成功完成。

自定义扩展

如果您想自定义分析功能,需要将spring-profiler-starter pom作为您扩展项目的父pom。然后,您可以使用项目暴露的接口进行扩展。更多详情,您可以参考spring-profiler-extension的实现。

<parent>
    <groupId>io.github.linyimin0812</groupId>
    <artifactId>spring-profiler-starter</artifactId>
    <version>最新版本</version>
</parent>

扩展接口

io.github.linyimin0812.profiler.api.EventListener
public interface EventListener extends Startable {

    /**
     * 应用启动期间调用
     */
    void start();

    /**
     * 应用启动完成后调用
     */
    void stop();
    
    /**
     * 需要增强的类
     * @param className

     * @return true: 增强,false: 不增强
     */
    boolean filter(String className);

    /**
     * 需要增强的方法(此方法依赖于filter(className)条件。只有当filter(className)返回true时才会执行)
     * @param methodName
     * @param methodTypes
     * @return true: 增强,false: 不增强
     */
    default boolean filter(String methodName, String[] methodTypes) {
        return true;
    }

    /**
     * 事件响应处理逻辑
     * @param event 触发事件
     */
    void onEvent(Event event);

    /**
     * 需要监听的事件
     * @return 需要监听的事件
     */
    List<Event.Type> listen();

}

start()stop()方法代表系统的生命周期,分别在应用启动开始和完成时调用。filter()方法指定需要增强的类/方法。listen()方法指定需要监听的事件,包括方法进入方法返回事件。onEvent()方法在监听的事件发生时被调用。

例如,以下是一个扩展,用于统计应用启动过程中java.net.URLClassLoader.findResource(String)方法的调用次数:

FindResourceCounter 示例
@MetaInfServices
public class FindResourceCounter implements EventListener {

    private final AtomicLong COUNT = new AtomicLong(0);

    @Override
    public boolean filter(String className) {
        return "java.net.URLClassLoader".equals(className);
    }

    @Override
    public boolean filter(String methodName, String[] methodTypes) {
       if (!"findResource".equals(methodName)) {
           return false;
       }

       return methodTypes != null && methodTypes.length == 1 && "java.lang.String".equals(methodTypes[0]);
    }

    @Override
    public void onEvent(Event event) {
        if (event instanceof AtEnterEvent) {
            // 进入findResource方法
        } else if (event instanceof AtExitEvent) {
            // findResource返回
        }

        // 调用次数计数
        COUNT.incrementAndGet();

    }

    @Override
    public List<Event.Type> listen() {
        return Arrays.asList(Event.Type.AT_ENTER, Event.Type.AT_EXIT);
    }

    @Override
    public void start() {
        System.out.println("============== 我的扩展开始 =============");
    }

    @Override
    public void stop() {
        System.out.println("============== 我的扩展结束 =============");
        System.out.println("findResource 调用次数: " + COUNT.get());
    }
}
需要注意的是,**EventListener 接口的实现类应该使用 @MetaInfServices 注解**。这是因为扩展接口是通过服务提供者接口(SPI)加载的。当你使用 `@MetaInfServices` 注解时,实现类会在代码编译过程中自动写入 `META-INF/services/io.github.linyimin0812.profiler.api.EventListener` 文件。如果不使用 `@MetaInfServices` 注解,你需要手动将实现类的完全限定名写入 META-INF/services/io.github.linyimin0812.profiler.api.EventListener 文件。否则,扩展实现将无法被加载。

打包和运行

spring-profiler-starter 的 pom 文件已经定义了一个打包插件,默认情况下会将生成的 JAR 文件复制到 $HOME/spring-startup-analyzer/extension 目录。

mvn clean package

按照安装部分的步骤安装完这个项目后,你可以执行上述打包命令。打包完成后,你可以按照应用启动部分的描述启动应用程序来加载扩展 JAR 文件。

🚀Spring 启动优化

生产环境启动时间优化

应用启动数据收集部分,你可以获取初始化时间较长的 Bean。由于 Spring 启动过程是单线程的,为了优化应用启动时间,你可以考虑将这些耗时 Bean 的初始化方法异步化。

注意:

  • 建议优先优化 Bean 的代码,从根本上解决初始化时间长的问题
  • 对于二方包或三方包中初始化时间较长的 Bean(无法优化代码),考虑对这些 Bean 进行异步初始化
  • 对于不依赖其他 Bean 的 Bean,可以放心地进行异步初始化,你可以通过查看Bean 加载时间部分的 Root Bean 来确定一个 Bean 是否依赖其他 Bean
  • 对于依赖其他 Bean 的 Bean,需要仔细分析。它们在应用启动过程中不应被其他 Bean 调用,否则可能会导致问题

支持异步的 Bean 类型

支持通过 @Bean、@PostConstruct 和 @ImportResource 初始化的 bean。示例:spring-boot-async-bean-demo

  1. 使用 @Bean(initMethod = "init") 注解的 Bean
@Bean(initMethod = "init")
public TestBean testBean() {
    return new TestBean();
}
  1. 使用 @PostConstruct 注解的 Bean
@Component
public class TestComponent {
    @PostConstruct
    public void init() throws InterruptedException {
        Thread.sleep(20 * 1000);
    }
}

使用方法

  1. 导入依赖
<dependency>
    <groupId>io.github.linyimin0812</groupId>
    <artifactId>spring-async-bean-starter</artifactId>
    <version>${最新版本}</version>
</dependency>
  1. 配置
# 异步 Bean 可能会在 Spring Bean 初始化顺序的末尾,这可能导致异步优化效果不佳。开启此配置以优先加载异步 Bean。
spring-startup-analyzer.boost.spring.async.bean-priority-load-enable=true
# 需要异步初始化的 Bean 名称
spring-startup-analyzer.boost.spring.async.bean-names=testBean,testComponent
# 初始化 Bean 的线程池核心大小
spring-startup-analyzer.boost.spring.async.init-bean-thread-pool-core-size=8
# 初始化 Bean 的线程池最大大小
spring-startup-analyzer.boost.spring.async.init-bean-thread-pool-max-size=8
  1. 检查 Bean 是否异步初始化

$HOME/spring-startup-analyzer/logs/async-init-bean.log 文件中查看日志。对于异步初始化的方法,将以以下格式写入一条日志:

async-init-bean, beanName: ${beanName}, async init method: ${initMethodName}

日常和预发环境启动时间优化

为了优化日常和预发环境的启动时间,我们可以考虑热插拔。该项目提供了一个命令行工具来实现修改代码的热插拔。

  1. release 下载 spring-startup-cli
  2. 在项目工作目录下执行命令行工具
java -jar spring-startup-cli.jar
  1. 使用 config 命令配置信息
config set
  1. 执行 reload 命令

🔗参考

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号