SpringBean的生命周期-Spring容器启动耗时分析(Bean启动耗时)-《Java笔记》

admin 2025-10-19 04:23:53 编程 来源:ZONE.CI 全球网 0 阅读模式

Java Spring

Spring bean 的生命周期

  • 实例化(instantiate), 用构造器创建一个对象
  • 字段赋值(populate)
  • 初始化(initialize), 执行bean配置里的init方法或者InitializingBean#afterPropertiesSet方法
  • 销毁(destruct)

实例化和字段赋值一般都很快,但是一些重型的bean被IOC容器创建时,需要调用远程服务或者执行耗时的操作,这些操作往往在init方法里实现。统计bean初始化耗时可以发现那些bean影响了系统的启动效率。业务方的bean可以推动业务优化,自己的bean也可以想方法优化性能。那么如何统计初始化的耗时呢?

Spring bean初始化源码分析

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean 观察执行初始化方法的逻辑

  1. protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  2. if (System.getSecurityManager() != null) {
  3. AccessController.doPrivileged(new PrivilegedAction<Object>() {
  4. @Override
  5. public Object run() {
  6. invokeAwareMethods(beanName, bean);
  7. return null;
  8. }
  9. }, getAccessControlContext());
  10. }
  11. else {
  12. invokeAwareMethods(beanName, bean);
  13. }
  14. Object wrappedBean = bean;
  15. if (mbd == null || !mbd.isSynthetic()) {
  16. // 初始化前spring提供的系统钩子
  17. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  18. }
  19. try {
  20. // 执行初始化方法
  21. invokeInitMethods(beanName, wrappedBean, mbd);
  22. }
  23. catch (Throwable ex) {
  24. throw new BeanCreationException(
  25. (mbd != null ? mbd.getResourceDescription() : null),
  26. beanName, "Invocation of init method failed", ex);
  27. }
  28. if (mbd == null || !mbd.isSynthetic()) {
  29. // 初始化后spring提供的系统钩子
  30. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  31. }
  32. return wrappedBean;
  33. }

applyBeanPostProcessorsBeforeInitialization做了什么?取出所有实现BeanPostProcessor的bean,逐个执行一遍postProcessBeforeInitialization方法。同理,applyBeanPostProcessorsAfterInitialization逻辑依然,只是执行的是postProcessInitialization方法。

  1. @Override
  2. public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
  3. throws BeansException {
  4. Object result = existingBean;
  5. for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
  6. result = beanProcessor.postProcessBeforeInitialization(result, beanName);
  7. if (result == null) {
  8. return result;
  9. }
  10. }
  11. return result;

Spring系统钩子 BeanPostProcessor

Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies. ApplicationContexts can autodetect BeanPostProcessor beans in their bean definitions and apply them to any beans subsequently created. Plain bean factories allow for programmatic registration of post-processors, applying to all beans created through this factory

BeanPostProcessor接口仅仅提供两个方法,用在在初始化bean的时候进行定制开发。

  1. public interface BeanPostProcessor {
  2. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  3. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  4. }

2022-04-29-19-06-28-673418.png

Bean初始化耗时功能开发demo

简单demo

  1. package org.dubbo.server.service.tool;
  2. import com.google.common.collect.Maps;
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.beans.factory.config.BeanPostProcessor;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Map;
  7. @Component
  8. public class TimeCostBeanPostProcessor implements BeanPostProcessor {
  9. Map<String, Long> costMap = Maps.newConcurrentMap();
  10. @Override
  11. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  12. costMap.put(beanName, System.currentTimeMillis());
  13. return bean;
  14. }
  15. @Override
  16. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  17. long start = costMap.get(beanName);
  18. long cost = System.currentTimeMillis() - start;
  19. if (cost > 0) {
  20. costMap.put(beanName, cost);
  21. System.out.println("class: " + bean.getClass().getName()
  22. + "\tbean: " + beanName
  23. + "\ttime" + cost);
  24. }
  25. return bean;
  26. }
  27. }
以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  16