Spring bean initialization time-consuming statistics

The life cycle of spring beans

  1. instantiate, creating an object with a constructor
  2. Field assignment (populate)
  3. Initialize (initialize), execute the init method or the InitializingBean#afterPropertiesSet method in the bean configuration
  4. 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;

}

insert image description here

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;
	}
}

Guess you like

Origin blog.csdn.net/bruce128/article/details/104419869