【309期】Spring Bean 容器启动耗时统计分析
点击上方“Java精选”,选择“设为星标”
别问别人为什么,多问自己凭什么!
下方有惊喜,留言必回,有问必答!
每一天进步一点点,是成功的开始...
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
观察执行初始化方法的逻辑
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化前spring提供的系统钩子
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 初始化后spring提供的系统钩子
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
取出所有实现BeanPostProcessor
的bean,逐个执行一遍postProcessBeforeInitialization
方法。
同理,applyBeanPostProcessorsAfterInitialization
逻辑依然,只是执行的是postProcessInitialization
方法。
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
spring系统钩子 BeanPostProcessor
BeanPostProcessor
接口仅仅提供两个方法,用在在初始化bean的时候进行定制开发。
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
bean初始化耗时功能开发demo
简单demo
package org.dubbo.server.service.tool;
import com.google.common.collect.Maps;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author LvSheng
**/
@Component
public class TimeCostBeanPostProcessor implements BeanPostProcessor {
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 {
long start = costMap.get(beanName);
long cost = System.currentTimeMillis() - start;
if (cost > 0) {
costMap.put(beanName, cost);
System.out.println("class: " + bean.getClass().getName()
+ "\tbean: " + beanName
+ "\ttime" + cost);
}
return bean;
}
}
作者:bruce128
https://blog.csdn.net/bruce128/article/details/104419869
公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!
3000+ 道各类技术面试题在线刷,最新、最全 Java 面试题!
【301期】SpringBoot 一个接口同时支持 form、form-data、json 优雅写法
【302期】SpringBoot 项目鉴权的 4 种方式,你了解吗?
【303期】SpringBoot + Redis 实现搜索栏热搜、不雅文字过滤功能
【304期】全文搜索引擎 Elasticsearch,这篇文章给讲透了!
最近有很多人问,有没有读者交流群!想知道如何加入?方式很简单,兴趣相投的朋友,只需要点击下方卡片,回复“加群”,即可无套路入交流群!