spring扩展点四:SmartInitializingSingleton的应用

前言

在这篇笔记中,主要记录SmartInitializingSingleton这个扩展点的应用,这个接口是在spring将所有的bean放入到spring容器之后,提供的一个扩展机制,在常用的框架中,我看到springcloud在将zk作为注册中心的时候,有用到这个扩展点

org.springframework.cloud.zookeeper.serviceregistry.ZookeeperServiceRegistry

在这里插入图片描述
目前还没有搞懂这个扩展点可以用来做什么,只是先记录一下原理和如何扩展,后续如果用到了,就再研究

原理

这个扩展点的调用逻辑是这样的

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

这里可以看到
1、这个方法是从beanDefinitionNames中获取到所有的beanName,然后依次遍历,对所有的beanDefinition进行初始化,也就是根据beanDefinition初始化bean对象
2、在初始化完所有的bean对象之后,会调用实现类的afterSingletonsInstantiated()方法,所以,我们知道,这个方法是在所有bean都放到了spring容器中之后,才被调用的

应用

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

上面是我自己写的一个demo,在初始化所有的bean之后,会执行我自己的业务逻辑

但是对于这个扩展点,确实在学习源码的过程中,看到的比较少,所以这里先只做一个简单的学习,后面有看到其他的框架使用到这个点的时候,再补充

猜你喜欢

转载自blog.csdn.net/CPLASF_/article/details/115266054