The life cycle of spring beans
- instantiate, creating an object with a constructor
- Field assignment (populate)
- Initialize (initialize), execute the init method or the InitializingBean#afterPropertiesSet method in the bean configuration
- destroy
Instantiation and field assignment are generally fast, but when some heavy beans are created by the IOC container, they need to call remote services or perform time-consuming operations, which are often implemented in the init method. Statistical bean initialization time consumption can be found that those beans affect the startup efficiency of the system. Beans on the business side can promote business optimization, and your own beans can also find ways to optimize performance.
So how to count the time spent on initialization?
Spring bean initialization source code analysis
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean Observe the logic of executing the initialization method
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;
}
What does applyBeanPostProcessorsBeforeInitialization do?
Take out all the beans that implement BeanPostProcessor, and execute the postProcessBeforeInitialization method one by one.
Similarly, the applyBeanPostProcessorsAfterInitialization logic remains the same, but the postProcessInitialization method is executed.
@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 system hook 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
The BeanPostProcessor interface only provides two methods for custom development when initializing beans.
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
Bean initialization time-consuming function development demo
simple 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
* @date 2020/2/20
**/
@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;
}
}