Spring Boot启动慢如何分析

news2024/11/17 21:39:19

如果发现项目启动慢,你知道怎么分析慢的原因吗?

分析方法

自定义监听器

SpringApplicationRunListener是Spring Boot中的一个接口,它的作用是在SpringApplication运行的各个阶段提供回调接口,以便我们可以在这些阶段执行自定义的逻辑。SpringApplicationRunListener接口定义了以下几个方法:

  1. starting: 在SpringApplication运行开始时调用。

  2. environmentPrepared: 在Environment准备好,但在ApplicationContext创建之前调用。

  3. contextPrepared: 在ApplicationContext准备好,但在其加载源之前调用。

  4. contextLoaded: 在ApplicationContext加载源后调用。

  5. started: 在ApplicationContext刷新并启动后,但在SpringApplication.run方法完成之前调用。

  6. running: 在SpringApplication.run方法完成后调用。

  7. failed: 在SpringApplication运行失败时调用。

通过实现SpringApplicationRunListener接口,我们可以在SpringApplication运行的各个阶段执行自定义的逻辑,例如初始化资源、清理资源、记录日志等。下面的代码例子展示继承SpringApplicationRunListener接口并打印相应日志

@Slf4j
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    // 这个构造函数不能少,否则反射生成实例会报错
    public MySpringApplicationRunListener(SpringApplication sa, String[] args) {
    }
    @Override
    public void starting() {
        log.info("starting {}", LocalDateTime.now());
    }
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        log.info("environmentPrepared {}", LocalDateTime.now());
    }
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        log.info("contextPrepared {}", LocalDateTime.now());
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        log.info("contextLoaded {}", LocalDateTime.now());
    }
    @Override
    public void started(ConfigurableApplicationContext context) {
        log.info("started {}", LocalDateTime.now());
    }
    @Override
    public void running(ConfigurableApplicationContext context) {
        log.info("running {}", LocalDateTime.now());
    }
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        log.info("failed {}", LocalDateTime.now());
    }
}

对于每个Bean初始化耗时的监控,我们可以通过继承BeanPostProcessor接口方式,BeanPostProcessor 是Spring框架的一个接口,它定义了两个回调方法:postProcessBeforeInitialization和postProcessAfterInitialization。这两个方法分别在Bean初始化前后被调用。你可以在这两个方法中记录时间,然后计算出Bean初始化的耗时。

@Component
public class BeanInitiateTimeCost implements BeanPostProcessor {
    private Map<String, Long> costMap = Maps.newConcurrentMap();
  
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        costMap.put(beanName, System.currentTimeMillis());
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (costMap.containsKey(beanName)) {
            Long start = costMap.get(beanName);
            long cost  = System.currentTimeMillis() - start;
            if (cost > 0) {
                costMap.put(beanName, cost);
                System.out.println("bean: " + beanName + "\ttime: " + cost);
            }
        }
        return bean;
    }
}

通过Actuator实现

前提条件: Spring Boot启动跟踪需要Spring boot的版本在2.4及以上。相关步骤

  1. 添加相关依赖

引入spring-boot-starter-actuator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.暴露startup路径

将下面配置加入到application.properties, 从而暴露startup链接

management.endpoints.web.exposure.include=startup

  1. 使用BufferingApplicationStartup的方式启动程序

在使用Spring Actuator分析Spring Boot启动慢的问题时,你需要在程序启动时启用BufferingApplicationStartup。这是因为Spring Boot 2.4.0及以上版本的Actuator的/actuator/startup端点使用BufferingApplicationStartup来收集启动过程的信息。

public class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
    }
}

在这个例子中,我们创建了一个BufferingApplicationStartup实例,并设置了缓冲区大小为2048。然后我们将这个BufferingApplicationStartup实例设置为SpringApplication的ApplicationStartup。

这样,当你启动应用程序并访问/actuator/startup端点时,你就可以看到启动过程的详细信息,包括每个bean的启动时间。你可以根据这些信息找出启动时间较长的bean,并进行优化。

返回结果分析

curl 'http://localhost:8080/actuator/startup' 返回JSON格式的数据,如下

{
    "springBootVersion": "2.6.3",
    "timeline": {
        "startTime": 1698287960.140000000,
        "events": [
            {
                "endTime": 1698287960.176000000,
                "duration": 0.018000000,
                "startupStep": {
                    "name": "spring.boot.application.starting",
                    "id": 0,
                    "tags": [
                        {
                            "key": "mainApplicationClass",
                            "value": "com.yuehuijiankang.blood.pressure.BloodPressureServiceApplication"
                        }
                    ],
                    "parentId": null
                },
                "startTime": 1698287960.158000000
            },
   ........         

startupStep中可以查看具体的执行步骤和耗时情况。借助jq工具可以方便分析JSON数据。比如,如果我们想查看Bean初始化最慢的前10个bean。我们可以执行下面命令:

curl 'http://localhost:8080/actuator/startup' -X POST | jq '[.timeline.events | sort_by(.duration) | reverse[] | select(.startupStep.name | match("spring.beans.instantiate")) | {beanName: .startupStep.tags[0].value, duration: .duration}] | .[:10]'

返回结果如下:

图片

总结

如果你发现Spring Boot项目启动慢,可以通过以下两种方法进行分析:

  1. 自定义监听器:通过实现SpringApplicationRunListener接口,可以在SpringApplication运行的各个阶段执行自定义的逻辑,例如记录每个阶段的时间。此外,可以通过实现BeanPostProcessor接口,记录Bean初始化前后的时间,从而计算出Bean初始化的耗时。

  2. 使用Actuator:Spring Boot 2.4及以上版本的Actuator提供了/actuator/startup端点,可以收集启动过程的信息。首先,需要在pom.xml文件中添加spring-boot-starter-actuator依赖,并在application.properties文件中暴露startup端点。然后,需要在程序启动时启用BufferingApplicationStartup。最后,通过访问/actuator/startup端点,可以看到启动过程的详细信息,包括每个bean的启动时间。

通过以上两种方法,可以找出启动时间较长的阶段或Bean,并进行相应的优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1314095.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PPT插件-好用的插件-放映笔、绘图板-大珩助手

放映笔 幻灯片放映时&#xff0c;工具在幻灯片的左下方&#xff0c;本工具在幻灯片的右侧&#xff0c;可以移动&#xff0c;可以方便在右侧讲课时候使用 绘图板 可在绘图板上写签名、绘制图画、写字等等&#xff0c;点画笔切换橡皮擦&#xff0c;点插入绘图&#xff0c;将背景…

jenkins学习19 - pipline 构建项目生成 allure报告并发送邮箱

前言 个人其实一直的不太喜欢用邮箱发送报告&#xff0c;测试报告用邮件通知这都是五六年前的事情了&#xff0c;但有部分小伙伴依然执着于发邮件报告通知。 这里整理了下发邮箱通知的教程。 配置你的邮箱 配置邮箱这一步最繁琐&#xff0c;由于每个人使用的邮箱不一样&…

欧拉市场份额达36.8%,服务器操作系统市场份额第一

[中国&#xff0c;北京&#xff0c;2023年12月15日] 以“崛起数字时代&#xff0c;引领数智未来”为主题的操作系统大会2023今日在北京国家会议中心举办&#xff0c;大会由开放原子开源基金会、中国电子技术标准化研究院、国家工业信息安全发展研究中心、中国软件行业协会共同主…

【Java】SpringBoot中实现Redis Stream队列

SpringBoot实现Redis Stream队列 前言 简单实现一下在SpringBoot中操作Redis Stream队列的方式&#xff0c;监听队列中的消息进行消费。 jdk&#xff1a;1.8 springboot-version&#xff1a;2.6.3 redis&#xff1a;5.0.1&#xff08;5版本以上才有Stream队列&#xff09;…

机器学习算法---回归

1. 线性回归&#xff08;Linear Regression&#xff09; 原理&#xff1a; 通过拟合一个线性方程来预测连续响应变量。线性回归假设特征和响应变量之间存在线性关系&#xff0c;并通过最小化误差的平方和来优化模型。优点&#xff1a; 简单、直观&#xff0c;易于理解和实现。…

力扣题:数字与字符串间转换-12.16

力扣题-12.16 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;640. 求解方程 解题思想&#xff1a;首先将方程按照“”进行划分&#xff0c;然后分别记录x的因数和常数项&#xff0c;最后进行返回的判断即可 class Solution(object):def solveEqu…

娱乐新拐点:TikTok如何改变我们的日常生活?

在数字时代的浪潮中&#xff0c;社交媒体平台不断涌现&#xff0c;其中TikTok以其独特的短视频内容在全球范围内掀起了一场娱乐革命。本文将深入探讨TikTok如何改变我们的日常生活&#xff0c;从社交互动、文化传播到个人创意表达&#xff0c;逐步改写了娱乐的新篇章。 短视频潮…

【Idea】SpringBoot项目中,jar包引用冲突异常的排查 / SM2算法中使用bcprov-jdk15to18的报错冲突问题

问题描述以及解决方法&#xff1a; 项目中使用了bcprov-jdk15to18 pom依赖&#xff0c;但是发现代码中引入的版本不正确。 追溯代码发现版本引入的是bcprov-jdk15on&#xff0c;而不是bcprov-jdk15to18&#xff0c;但是我找了半天pom依赖也没有发现有引入bcprov-jdk15on依赖。…

【MySQL】:表的增加和查寻

表的增查 一.Create(增)1.基本插入2.插入是否更新3.替换 二.Retrieve(查)1.select列1.全列查询2.指定列查询3.查询字段为表达式4.结果去重 2.where条件查询1.运算符2.运算符使用 3.结果排序4.筛选分页结果 一.Create(增) 1.基本插入 对于表的增加&#xff0c;前面已经用过很多…

什么是供应链安全及其工作原理?

6000公里长的丝绸之路将丝绸、谷物和其他货物从中国运送到帕尔米拉。尽管蒙古治下的和平保护丝绸之路免受海盗、强盗和内部盗窃的侵害&#xff0c;但商人仍然装备精良&#xff0c;并依赖于大型商队旅行和战略性放置的小型堡垒所提供的安全。 为什么供应链安全很重要&#xff1…

(1)(1.8) MSP(MultiWii 串行协议)(4.1 版)

文章目录 前言 1 协议概述 2 配置 3 参数说明 前言 ArduPilot 支持 MSP 协议&#xff0c;可通过任何串行端口进行遥测和传感器。这允许 ArduPilot 将其遥测数据发送到 MSP 兼容设备&#xff08;如大疆护目镜&#xff09;&#xff0c;用于屏幕显示&#xff08;OSD&#xff…

微服务保护--熔断降级

1.熔断降级介绍 熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例&#xff0c;如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求&#xff1b;而当服务恢复时&#xff0c;断路器会放行访问该服务的请求。 断路器控制熔断和放行…

ISCTF(a)

where_is_the_flag 答案应该被分成了三份了 蚁剑连接看看 第一个 第二个 第三个&#xff0c;在www下 Yunxi{0797d78c-0cb2-4cfb-87e6-f9c102f716f3} 命令执行 POST : 1 system ( tac flag.php ); 1 system ( tac /flag2 ); 1 system ( env ); 1z_Ssql 使用万能密码 后…

【LeetCode刷题笔记(7-1)】【Python】【四数之和】【哈希表】【中等】

文章目录 四数之和题目描述示例 1示例 2提示解决方案1&#xff1a;【四层遍历查找】解决方案2&#xff1a;【哈希表】【三层遍历】 结束语 四数之和 四数之和 题目描述 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件…

鸿蒙原生应用/元服务开发-Stage模型能力接口(五)

说明 Common模块将二级模块API组织在一起方便开发者进行导出。本模块首批接口从API version 9开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接口仅可在Stage模型下使用 二、 导入模块 import common from ohos.app.ability.common; 三、 …

动手学深度学习-自然语言处理:应用

自然语言处理中的应用主要有哪些&#xff1f; 自然语言处理&#xff1a;应用 情感分析及数据集 情感分析研究人们在文本中的情感&#xff0c;这被认为是一个文本分类问题&#xff0c;它将可变长度的文本序列进行转换为固定长度的文本类别。经过预处理后&#xff0c;我们可以使…

ros2+xml格式launch文件示例代码(重要内容)

源自githubeasy_ros2_launch_talk/easy_launch_demo/launch/demo_launch.xml at main tylerjw/easy_ros2_launch_talk GitHub <launch><arg name"robot_ip" default"xxx.yyy.zzz.www" /><arg name"use_fake_hardware" default…

「Verilog学习笔记」RAM的简单实现

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1ns module ram_mod(input clk,input rst_n,input write_en,input [7:0]write_addr,input [3:0]write_data,input read_en,input [7:0]read_addr,output reg…

鸿蒙开发ArkTS语言-XML解析

XML概述 XML&#xff08;可扩展标记语言&#xff09;是一种用于描述数据的标记语言&#xff0c;旨在提供一种通用的方式来传输和存储数据&#xff0c;特别是Web应用程序中经常使用的数据。XML并不预定义标记。因此&#xff0c;XML更加灵活&#xff0c;并且可以适用于广泛的应用…

黑马点评04集群下的并发安全

实战篇-08.优惠券秒杀-集群下的线程并发安全问题_哔哩哔哩_bilibili 为了应对高并发&#xff0c;需要把项目部署到多个机器构成集群&#xff0c;所以需要配置nginx。 1.如何模拟集群 通过idea的ctrl d修改配置&#xff0c;实现多个tomcat运行模拟集群 然后在nginx上配置节点&…