spring如何通过实现BeanPostProcessor接口计算并打印每一个bean的加载耗时
文章目录
- 实现说明:
- 注意事项:
要在Spring中通过
BeanPostProcessor
接口计算并打印每个Bean的加载耗时,我们可以利用该接口的两个回调方法记录Bean初始化前后的时间戳,然后计算时间差。
以下是实现方案:
- 首先创建一个实现
BeanPostProcessor
接口的类- 使用线程安全的Map存储每个Bean的初始化开始时间
- 在
postProcessBeforeInitialization
中记录开始时间- 在
postProcessAfterInitialization
中计算并打印耗时
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 计算并打印每个Bean的加载耗时*/
@Component
public class BeanInitializationTimer implements BeanPostProcessor {// 使用线程安全的Map存储Bean初始化开始时间private final Map<String, Long> startTimeMap = new ConcurrentHashMap<>();/*** Bean初始化之前调用,记录开始时间*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 记录当前时间戳作为开始时间startTimeMap.put(beanName, System.currentTimeMillis());return bean;}/*** Bean初始化之后调用,计算并打印耗时*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 获取开始时间Long startTime = startTimeMap.get(beanName);if (startTime != null) {// 计算耗时long endTime = System.currentTimeMillis();long duration = endTime - startTime;// 打印Bean加载耗时信息System.out.printf("Bean '%s' 初始化完成,类型: %s,耗时: %d ms%n",beanName, bean.getClass().getSimpleName(), duration);// 移除已处理的Bean记录,释放内存startTimeMap.remove(beanName);}return bean;}
}
实现说明:
- 组件注册:通过
@Component
注解将该处理器注册为Spring组件,Spring会自动发现并使用它- 时间记录:
- 在
postProcessBeforeInitialization
方法中,记录每个Bean开始初始化的时间戳- 使用
ConcurrentHashMap
确保在多线程环境下的线程安全
- 耗时计算:
- 在
postProcessAfterInitialization
方法中,计算当前时间与开始时间的差值- 打印Bean名称、类型和初始化耗时
- 处理完成后从Map中移除记录,避免内存泄漏
- 使用方式:只需将该类放入Spring扫描路径下,Spring容器启动时就会自动使用该处理器,无需额外配置
注意事项:
- 该耗时包括Bean的初始化方法(如
@PostConstruct
标注的方法)执行时间- 如果Bean没有初始化方法,耗时会非常短
- 对于懒加载的Bean,会在第一次被获取时才会计算耗时
- 输出结果会显示在控制台,按Bean初始化完成的顺序打印
通过这种方式,你可以很方便地监控Spring容器中所有Bean的初始化性能,识别出初始化耗时较长的Bean,为性能优化提供依据。