Spring extension point 4: Application of SmartInitializingSingleton

Preface

In this note, I mainly record the application of the extension point SmartInitializingSingleton. This interface is an extension mechanism provided by spring after putting all beans into the spring container. In commonly used frameworks, I see that springcloud is adding zk When used as a registry, this extension point is useful

org.springframework.cloud.zookeeper.serviceregistry.ZookeeperServiceRegistry

Insert picture description here
I have not yet understood what this extension point can be used for, just record the principle and how to extend it first, and then study it if it is used later.

principle

The calling logic of this extension point is like this

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
	org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
/**
 * 在该方法中,主要完成了以下几个操作
 * 1.遍历所有的beanDefinitionName,完成合并bean的操作
 * 2.如果当前bean是单实例的、非懒加载的、非抽象bean,就调用bean的后置处理器 完成实例化的操作
 * 3.在所有bean都实例化完成之后,调用实现了SmartInitializingSingleton接口的bean对象,完成org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()方法的调用
 * @throws BeansException
 */
@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isDebugEnabled()) {
		logger.debug("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	/**
	 * 在将beanDefinition存入BeanDefinitionMap的同时,会将beanName存入到一个list集合中
	 * 这里直接从beanDefinitionNames这个集合中,获取所有要实例化的bean的name
	 */
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	//触发所有非延迟加载单实例bean的加载,加载的过程就是调用getBean()方法  上面获取到的是所有的beanName
	for (String beanName : beanNames) {
		/**
		 * 合并父类beanDefinition;在前面初始化bean的时候,就已经合并了,这里是再判断一次,如果当前bean没有合并,就合并;如果已经合并了,就直接从
		 * 对应的map集合中取出合并之后的beanDefinition
		 *
		 * 之所以要做beanDefinition的merge操作,是因为有些beanDefinition是RootBeanDefinition的子类,如果直接用子BeanDefinition去实例化,可能会有问题
		 * 因为一个子BeanDefinition可以继承父beanDefinition,一些共性的信息可以放到父BeanDefinition中,所以,在对bean进行初始化的时候,都要对相应的beanDefinition进行合并的操作,得到RootBeanDefinition;比如:
		 *  RootBeanDefinitionA设置需要注入name属性
		 *  BeanDefinitionB设置需要注入type属性,再设置BeanDefinitionB 继承RootBeanDefinitionA,假如在这里不合并rootBeanDefinitionA,那么B这个bd需要注入的属性就只有type,不会有name,那也就不是我们想要的bd了;所以这里要把子bd的属性合并到新的RootBeanDefinition中
		 *
		 *  并且,spring在初始化bean的过程中,会对bd进行一些校验(比如:是否是单实例的,是否是抽象的等);所以:这里要先把bd进行合并,获取到父类的bd属性信息
		 */
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 非抽象、非懒加载、单实例的bean
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			//判断当前bean是否是beanFactory;如果是factoryBean,在beanName前面加上 &
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				//这里是去完成bean的实例化
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	/**
	 * 这里应该也算是spring提供的一个扩展点之一
	 * 在所有的bean都实例化完成之后,会调用org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()
	 * 来完成程序员的一些业务逻辑操作
	 */
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

Here you can see
1. This method is to get all the beanNames from beanDefinitionNames, and then traverse in turn to initialize all the beanDefinitions, that is, initialize the bean object according to the beanDefinition
2. After all the bean objects are initialized, the implementation will be called The afterSingletonsInstantiated() method of the class, so we know that this method is called after all beans are placed in the spring container

application

@Configuration
@Import(MySmartInitializingSingleton.class)
public class AppConfig {
}
public class MySmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("在所有bean都被放入到spring容器之后,执行自己的业务逻辑");
    }
}
public class TestSmartInitializingSingleton {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

The above is a demo written by myself. After all the beans are initialized, my own business logic will be executed.

But for this extension point, I did see less in the process of learning the source code, so I will only do a simple study first, and then I will add when I see other frameworks using this point.

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/115266054