spring如何通过实现BeanPostProcessor接口计算并打印每一个bean的加载耗时

文章目录

要在Spring中通过BeanPostProcessor接口计算并打印每个Bean的加载耗时,我们可以利用该接口的两个回调方法记录Bean初始化前后的时间戳,然后计算时间差。
以下是实现方案:

  1. 首先创建一个实现BeanPostProcessor接口的类
  2. 使用线程安全的Map存储每个Bean的初始化开始时间
  3. postProcessBeforeInitialization中记录开始时间
  4. postProcessAfterInitialization中计算并打印耗时
java 复制代码
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初始化之前调用,记录开始时间
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 记录当前时间戳作为开始时间
        startTimeMap.put(beanName, System.currentTimeMillis());
        return bean;
    }

    /**
     * Bean初始化之后调用,计算并打印耗时
     */
    @Override
    public 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;
    }
}

实现说明:

  1. 组件注册 :通过@Component注解将该处理器注册为Spring组件,Spring会自动发现并使用它
  2. 时间记录
  • postProcessBeforeInitialization方法中,记录每个Bean开始初始化的时间戳
  • 使用ConcurrentHashMap确保在多线程环境下的线程安全
  1. 耗时计算
  • postProcessAfterInitialization方法中,计算当前时间与开始时间的差值
  • 打印Bean名称、类型和初始化耗时
  • 处理完成后从Map中移除记录,避免内存泄漏
  1. 使用方式:只需将该类放入Spring扫描路径下,Spring容器启动时就会自动使用该处理器,无需额外配置

注意事项:

  • 该耗时包括Bean的初始化方法(如@PostConstruct标注的方法)执行时间
  • 如果Bean没有初始化方法,耗时会非常短
  • 对于懒加载的Bean,会在第一次被获取时才会计算耗时
  • 输出结果会显示在控制台,按Bean初始化完成的顺序打印

通过这种方式,你可以很方便地监控Spring容器中所有Bean的初始化性能,识别出初始化耗时较长的Bean,为性能优化提供依据。

相关推荐
若鱼191914 分钟前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
跳动的梦想家h1 小时前
环境配置 + AI 提效双管齐下
java·vue.js·spring
独断万古他化2 小时前
【Spring 原理】Bean 的作用域与生命周期
java·后端·spring
vx1_Biye_Design2 小时前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven
Hx_Ma163 小时前
SpringBoot数据源自动管理
java·spring boot·spring
java1234_小锋3 小时前
Java高频面试题:Spring和SpringBoot的关系和区别?
java·spring boot·spring
梵得儿SHI4 小时前
(第十篇)Spring AI 核心技术攻坚全梳理:企业级能力矩阵 + 四大技术栈攻坚 + 性能优化 Checklist + 实战项目预告
java·人工智能·spring·rag·企业级ai应用·springai技术体系·多模态和安全防护
逍遥德4 小时前
Sring事务详解之02.如何使用编程式事务?
java·服务器·数据库·后端·sql·spring
老毛肚13 小时前
MyBatis插件原理及Spring集成
java·spring·mybatis
shuair21 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存