Spring 容器启动耗时统计
为了了解 Spring 为什么会启动那么久,于是看了看怎么统计一下加载 Bean 的耗时。
极简版
几行代码搞定。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;import java.util.HashMap;
import java.util.Map;public class SpringBeanAnalyse implements BeanPostProcessor {private static final Map<String, Long> mapBeanTime = new HashMap<>();@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {mapBeanTime.put(beanName, System.currentTimeMillis());return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {Long begin = mapBeanTime.get(beanName);if (begin != null) {long ell = System.currentTimeMillis() - begin;System.out.println(beanName + " 耗时: " + ell);}return bean;}
}
使用方法:
@Bean
SpringBeanAnalyse SpringBeanAnalyse() {return new SpringBeanAnalyse();
}
效果如图:
问题是没有排序,看比较费劲。
高配版
于是,高配版出场了。它更为成熟壮健,并有排序功能。
原理
Bean 启动时间抓取,主要是围绕 Spring Bean 生命周期。BeanPostProcessor 相关方法
- postProcessBeforeInstantiation: 实例化前
- postProcessAfterInstantiation: 实例化后
- postProcessBeforeInitialization: 初始化前
- postProcessAfterInitialization: 初始化后
注意:实现MergedBeanDefinitionPostProcessor
, 主要是为了调整当前 BeanPostProcessor
的执行顺序到最后, 具体参考BeanPostProcessor
注册流程
org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
,详见
源码
首先是一个 Bean。
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
class Statistics {private String beanName;private long beforeInstantiationTime;private long afterInstantiationTime;private long beforeInitializationTime;private long afterInitializationTime;public long calculateTotalCostTime() {return calculateInstantiationCostTime() + calculateInitializationCostTime();}public long calculateInstantiationCostTime() {return afterInstantiationTime - beforeInstantiationTime;}public long calculateInitializationCostTime() {return afterInitializationTime - beforeInitializationTime;}public String toConsoleString() {return "\t" + getBeanName() + "\t" + calculateTotalCostTime() + "\t\n";}
}
StartupTimeMetric
源码:
import com.ajaxjs.util.logger.LogHelper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.PriorityOrdered;import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;/*** 用于调优的处理器*/
public class StartupTimeMetric implements InstantiationAwareBeanPostProcessor, PriorityOrdered, ApplicationListener<ContextRefreshedEvent>, MergedBeanDefinitionPostProcessor {private static final LogHelper LOGGER = LogHelper.getLog(StartupTimeMetric.class);private final Map<String, Statistics> statisticsMap = new TreeMap<>();/*** InstantiationAwareBeanPostProcessor 中自定义的方法 在方法实例化之前执行 Bean 对象还没有*/@Overridepublic Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {String beanClassName = beanClass.getName();Statistics s = Statistics.builder().beanName(beanClassName).build();s.setBeforeInstantiationTime(System.currentTimeMillis());statisticsMap.put(beanClassName, s);return null;}/*** InstantiationAwareBeanPostProcessor 中自定义的方法 在方法实例化之后执行 Bean 对象已经创建出来了*/@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {String beanClassName = bean.getClass().getName();Statistics s = statisticsMap.get(beanClassName);if (s != null)s.setAfterInstantiationTime(System.currentTimeMillis());return true;}/*** BeanPostProcessor 接口中的方法 在 Bean 的自定义初始化方法之前执行 Bean 对象已经存在了*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {String beanClassName = bean.getClass().getName();Statistics s = statisticsMap.getOrDefault(beanClassName, Statistics.builder().beanName(beanClassName).build());s.setBeforeInitializationTime(System.currentTimeMillis());statisticsMap.putIfAbsent(beanClassName, s);return bean;}/*** BeanPostProcessor 接口中的方法 在 Bean 的自定义初始化方法执行完成之后执行 Bean 对象已经存在了*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {String beanClassName = bean.getClass().getName();Statistics s = statisticsMap.get(beanClassName);if (s != null)s.setAfterInitializationTime(System.currentTimeMillis());return bean;}@Overridepublic int getOrder() {return PriorityOrdered.HIGHEST_PRECEDENCE;}private static final AtomicBoolean START_LOCK = new AtomicBoolean(false);@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {LOGGER.info("Spring 容器启动完成");if (START_LOCK.compareAndSet(false, true)) {List<Statistics> sList = statisticsMap.values().stream().sorted(Comparator.comparing(Statistics::calculateTotalCostTime).reversed()).collect(Collectors.toList());StringBuilder sb = new StringBuilder();sList.forEach(_s -> sb.append(_s.toConsoleString()));LOGGER.info("ApplicationStartupTimeMetric:\n" + sb);}}@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {}
}
参见《应用启动加速-并发初始化spring bean》
相关文章:
Spring 容器启动耗时统计
为了了解 Spring 为什么会启动那么久,于是看了看怎么统计一下加载 Bean 的耗时。 极简版 几行代码搞定。 import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;import java.util.HashMap; imp…...
1. 优化算法学习
参考文献 1609:An overview of gradient descent optimization algorithms 从 SGD 到 Adam —— 深度学习优化算法概览(一) - 知乎 机器学习札记 - 知乎...
再获荣誉丨通付盾WAAP解决方案获“金鼎奖”优秀金融科技解决方案
今年四月,2023中国国际金融展在首钢会展中心成功落下帷幕。中国国际金融展作为金融开放创新成果的展示、交流、传播平台,历经多年发展,已成为展示中国金融发展成就、宣传金融改革成果、促进金融产业创新和推动金融信息化发展的有效平台。 “金鼎奖”评选…...
【腾讯云 TDSQL-C Serverless 产品测评】“橡皮筋“一样的数据库『MySQL高压篇』
【腾讯云 TDSQL-C Serverless 产品测评】"橡皮筋"一样的数据库 活动介绍服务一览何为TDSQL ?Serverless 似曾相识? 降本增效,不再口号?动手环节 --- "压力"山大实验前瞻稍作简介资源扩缩范围(CCU&…...
python http文件上传
server端代码 import os import cgi from http.server import SimpleHTTPRequestHandler, HTTPServer# 服务器地址和端口 host = 0.0.0.0 port = 8080# 处理文件上传的请求 class FileUploadHandler(SimpleHTTPRequestHandler):def do_POST(self):# 解析多部分表单数据form = …...
Android学习之路(9) Intent
Intent 是一个消息传递对象,您可以用来从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个: 启动 Activity Activity 表示应用中的一个屏幕。通过将 Intent 传递给 startActivity()&…...
vue项目配置git提交规范
vue项目配置git提交规范 一、背景介绍二、husky、lint-staged、commitlint/cli1.husky2.lint-staged3.commitlint/cli 三、具体使用1.安装依赖2.运行初始化脚本3.在package.json中配置lint-staged4.根目录新增 commitlint.config.js 4.提交测试1.提示信息格式错误时2.eslint校验…...
影响交叉导轨运行速度的因素有哪些?
交叉导轨具有精度高,速度快,承载能力大、结构简单等特点,被广泛应用在固晶机、点胶设备、自动化设备、OA机器及其周边机器、测定器、印刷基板开孔机,精密机器,光学测试仪、光学工作台、操纵机构、X 射缐装置等的滑座部…...
List转Map
一、list转map Map<Long, User> maps userList.stream().collect(Collectors.toMap(User::getId,Function.identity())); 看来还是使用JDK 1.8方便一些。 二、另外,转换成map的时候,可能出现key一样的情况,如果不指定一个覆盖规则&…...
ES:一次分片设计问题导致的故障
### 现象: 1. 单节点CPU持续高 2.写入骤降 3.线程池队列积压,但没有reject 4.使用方没有记录日志 ### 排查 1.ES监控 只能看到相应的结果指标,无法反应出原因。 2.ES日志:大量日志打印相关异常(routate等调用栈&a…...
vue 简单实验 自定义组件 综合应用 传参数 循环
1.代码 <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"todo-list-app"><ol><!--现在我们为每个 todo-item 提供 todo 对象todo 对象是变量,即其内容可以是动态的。…...
【OpenCV实战】2.OpenCV基本数据类型实战
OpenCV基本数据类型实战 〇、实战内容1 OpenCV helloworld1.1 文件结构类型1.2 CMakeList.txt1.3 Helloworld 2. Image的基本操作3. OpenCV 基本数据类型4. 读取图片的像素 & 遍历图片4.1 获取制定像素4.2 遍历图片 5. 图片反色5.1 方法1 :遍历5.2 方法2 &#…...
MyBatis进阶:告别SQL注入!MyBatis分页与特殊字符的正确使用方式
目录 引言 一、使用正确的方式实现分页 1.1.什么是分页 1.2.MyBatis中的分页实现方式 1.3.避免SQL注入的技巧 二、特殊字符的正确使用方式 2.1.什么是特殊字符 2.2.特殊字符在SQL查询中的作用 2.3.如何避免特殊字符引起的问题 2.3.1.使用CDATA区段 2.3.2.使用实体引…...
安装Node(脚手架)
目录 一,安装node(脚手架)1.1, 配置vue.config.js1.2, vue-cli3x的目录介绍1.3, package.json 最后 一,安装node(脚手架) 从官网直接下载安装即可,自带npm包管…...
R语言10-R语言中的循环结构
在R语言中,有几种常用的循环结构,可以用来多次执行特定的代码块。以下是其中的两种主要循环结构: for循环: for 循环用于按照一定的步长迭代一个序列,通常用于执行固定次数的循环。 for (i in 1:5) {print(i) }while…...
【Spring】一次性打包学透 Spring | 阿Q送书第五期
文章目录 如何竭尽可能确保大家学透Spring1. 内容全面且细致2. 主题实用且本土化3. 案例系统且完善4. 知识有趣且深刻 关于作者丁雪丰业内专家推图书热卖留言提前获赠书 不知从何时开始,Spring 这个词开始频繁地出现在 Java 服务端开发者的日常工作中,很…...
第 7 章 排序算法(4)(插入排序)
7.7插入排序 7.7.1插入排序法介绍: 插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。 7.7.2插入排序法思想: 插入排序(Insertion Sorting)的基本思想是:把n个待排…...
JavsScript知识框架
JavaScript学习框架性总结 要系统性地精通 JavaScript,需要涵盖广泛的知识点,从基础到高级。以下是一些需要掌握的关键知识点(当然不止这些): 基础语法和核心概念: 变量、数据类型、运算符作用域闭包this …...
el-input添加自定义指令只允许输入中文/英文/数字,兼容输入法事件
省流 script: directives: {regexp: {inserted: (el, binding, vnode) > {let composition falseconst formatValue function (e) {if (composition) return// vnode.componentInstance组件实例vnode.componentInstance.$emit(input, e.target.value.replace(/[^\u4e00-…...
0基础学习VR全景平台篇 第89篇:智慧眼-安放热点
一、功能说明 安放热点,是智慧眼成员们正式进入城市化管理的第一步,即发现问题后以安放热点的形式进行标记,再由其他的角色成员对该热点内容作出如核实、处理、确认完结等操作(具体流程根据项目实际情况而定)。 二、…...
java中用SXSSFWorkbook把多个list数据和单个实体dto导出到excel如何导出到多个sheet页详细实例?(亲测)
以下是一个详细的示例,展示了如何使用SXSSFWorkbook将多个List数据和单个实体DTO导出到多个Sheet页: import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.S…...
SpringBoot 01 如何创建 和pom的解析
目录 1 Springboot的创建 步骤 2 项目的书写和运行 创建service包并在其下写一个service文件 项目的运行 pom文件的一些配置 parent web test 打包 打包过程 1 Springboot的创建 步骤 首先new一个新项目 然后依照如下创建 2 项目的书写和运行 创建service包并…...
axios详解
1.安装axios:npm install axios,等待安装完毕即可 2.引用axios:在需要使用的页面中引用 import axios from axios即可 get和post大同小异,一个是跟在url后面一个是跟在请求体里的 axios({method:"post/get&quo…...
Docker分布式仓库
Harbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器,由 vmware 开源,其通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有 Registry 服务器,…...
SQL注入之万能用户名
文章目录 分析代码原理实现 分析代码 在安装的cms数据库目录C:\phpStudy\WWW\cms\admin下找到login.action.php文件,查看第20行,发现如下php代码: $user_row $db->getOneRow("select userid from cms_users where username "…...
ubuntu20搭建环境使用的一下指令
1.更新源 sudo vim etc/apt/sources.listdeb http://mirrors.aliyun.com/ubuntu/ xenial main deb-src http://mirrors.aliyun.com/ubuntu/ xenial maindeb http://mirrors.aliyun.com/ubuntu/ xenial-updates main deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates…...
GAN(生成对抗网络)
简介:GAN生成对抗网络本质上是一种思想,其依靠神经网络能够拟合任意函数的能力,设计了一种架构来实现数据的生成。 原理:GAN的原理就是最小化生成器Generator的损失,但是在最小化损失的过程中加入了一个约束࿰…...
实时同步ES技术选型:Mysql+Canal+Adapter+ES+Kibana
基于之前的文章,精简操作而来 让ELK在同一个docker网络下通过名字直接访问Ubuntu服务器ELK部署与实践使用 Docker 部署 canal 服务实现MySQL和ES实时同步Docker部署ES服务,canal全量同步的时候内存爆炸,ES/Canal Adapter自动关闭,…...
禅道后台命令执行漏洞
漏洞简介 禅道是第一款国产的开源项目管理软件。它集产品管理、项目管理、质量管理、文档管理、 组织管理和事务管理于一体,是一款专业的研发项目管理软件,完整地覆盖了项目管理的核心流程。 禅道管理思想注重实效,功能完备丰富,…...
基于Spark+django的国漫推荐系统--计算机毕业设计项目
近年来,随着互联网的蓬勃发展,企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,随着各行业的不断发展,基…...
千博医院网站模板/如何建立电商平台
WINDOWS 2008 2012 1016等,桌面默认没有我的电脑,文档,网络等图标,操作时候,就不方便,以下提供几种方法。方法一:本地输入运行如果是在Windows Server 2012本地控制台下,直接按Win(键…...
印度人通过什么网站做国际贸易/网站数据
第七章Simulink 基础Chapter 7: Introduction to Simulink一.Simulink 初步(Primer of Simulink)MATLABSimulink是一个动态仿真系统,用于对动态系统进行仿真和分析,预先模拟实际系统的特性和响应,根据设计和使用要求,对…...
免费域名做私服网站/太原seo排名收费
PostgreSQL的热备和恢复(本贴在CU的PG版没人看,希望对各位有用) 二, 03 五月 2005 11:48 为什么要写这篇文章?因为我看了一下,国内所有的PostgreSQL教程都没有很详细的介绍该功能,而相反,国内的Oracle文章对这块非常…...
自己做免费网站吗/怎么联系百度客服
--对于分区表constraint_exclusion 这个参数需要配置为partition或on postgres# show constraint_exclusion ;constraint_exclusion ----------------------partition--创建父子表, 用于存储分区数据 create table t(id int primary key); create table t1(like t including a…...
黄酒的电商网页设计网站/广州seo优化排名公司
2019独角兽企业重金招聘Python工程师标准>>> git目录 这个博客有一个好处,不需要依附于apach或者Nginx,只需要使用jekyll ,速度很快。 安装ruby,使用rvm,步骤:(参考) 1: gpg --keyserver hkp://…...
python mysql开发网站开发/免费自助建站平台
其实最初听到数据挖掘,觉得很高大上,没有过多的思考,挖来的数据能干嘛呢。 刚看到一篇关于数据分析的文章,大概内容就是获取用户评论,然后对评论进行分析,找出客户不满意的地方,但这种分析还是人…...