Spring扩展点系列-SmartInstantiationAwareBeanPostProcessor

文章目录

简介

spring容器中Bean的生命周期内所有可扩展的点的调用顺序

扩展接口 实现接口
ApplicationContextlnitializer initialize
AbstractApplicationContext refreshe
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor postProcessBeanFactory
BeanFactoryPostProcessor postProcessBeanFactory
instantiationAwareBeanPostProcessor postProcessBeforelnstantiation
SmartlnstantiationAwareBeanPostProcessor determineCandidateConstructors
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor postProcessAfterlnstantiation
SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference
BeanNameAware setBeanName
BeanFactoryAware postProcessPropertyValues
ApplicationContextAwareProcessor invokeAwarelnterfaces
InstantiationAwareBeanPostProcessor postProcessBeforelnstantiation
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBean destroy

提到SmartInstantiationAwareBeanPostProcessor,这里就要说到三级缓存的话题,spring引入一个三级缓存来解决循环依赖和AOP的问题。三级缓存的key还是为beanName,但是value是一个函数(ObjectFactory#getBean方法),在该函数中执行获取早期对象的逻辑:getEarlyBeanReference方法。 在getEarlyBeanReference方法中,Spring会调用所有SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法,通过该方法可以修改早期对象的属性或者替换早期对象。这个是Spring留给开发者的另一个扩展点。

源码分析

该扩展接口有3个触发回调方法

java 复制代码
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

	/**
	 * 预测最终从此处理器的回调中返回的 bean 的类型。
	 * @param beanClass  bean 的原始类
	 * @param beanName   bean 的名称
	 */
	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * 确定要用于给定 bean 的候选构造函数。默认实现返回null   该回调发生在 postProcessBeforeInstantiation之后
 	 * @param beanClass  bean 的原始类
	 * @param beanName   bean 的名称
	 */
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {

		return null;
	}

	/**
	 * 获取对指定 bean 的早期访问的引用,通常用于解决循环引用  该回调发生在 postProcessAfterInstantiation之后
	 * 此回调使后处理器有机会尽早公开包装器 - 即在目标 bean 实例完全初始化之前。公开的对象应等同于否则将公开的内容
	 * @param beanClass  bean 的原始类
	 * @param beanName   bean 的名称
	 */
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

接下来我们来看看调用的一个链路getBean=》doGetBean=》createBean=》doCreateBean

org.springframework.beans.factory.support.AbstractBeanFactory#getBean

java 复制代码
@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

java 复制代码
protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	// Create bean instance.
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
	//.....源码省略
}

createBean方法主要调用doCreateBean方法,在doCreateBean调用之前会先调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation拦截bean的实例化,如果这里的后置处理器返回了bean,则不会到后面的doCreateBean方法中
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean

java 复制代码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
		
	//.....源码省略
	try {
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	//.....源码省略
}			

对于循环依赖的情况,getBean(A)--》存入正在创建缓存--》存入三级缓存--》populateBean(A)--》getBean(B)--》populateBean(B)--》getBean(A)--》getSingleton(A),当在populateBean(B)的过程中调用getSingleton(A)的时候,明显一级缓存和二级缓存都为空,但是三级缓存不为空,所以会通过三级缓存获取bean,三级缓存的创建逻辑如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

	//.....省略

	// 缓存单例,以便能够解决循环引用
	// 即使是由 BeanFactoryAware 等生命周期接口触发。
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
	//.....省略

这个getEarlyBeanReference方法的逻辑很简单,该方法主要就是对SmartInstantiationAwareBeanPostProcessor后置处理器的调用,而循环依赖时的AOP就是通过这个SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法实现的,相关的具体类是AnnotationAwareAspectJAutoProxyCreator

java 复制代码
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	Object exposedObject = bean;
	//如果容器中有InstantiationAwareBeanPostProcessors后置处理器
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
			//调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
			exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
		}
	}
	return exposedObject;
}

在getSingleton方法的逻辑中,先从一级缓存获取,如果一级缓存没有找到,那么如果获取的bean正在创建中,则从二级缓存获取,如果二级缓存没有找到,那么从三级缓存获取,三级缓存中存的是ObjectFactory实现,最终会调用其getBean方法获取bean,然后存入二级缓存中,同时清除三级缓存。同时提供了一个allowEarlyReference参数控制是否能从三级缓存中获取
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton

java 复制代码
/**
 * 返回以给定名称注册的(原始)单例对象。检查已实例化的单例,并允许对当前创建的单例进行早期引用(解决循环引用)。
 * @param beanName 要查找的 bean 的名称
 * @param allowEarlyReference 是否应创建早期引用
 * @return 已注册的单例对象,如果未找到则返回 null
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
			synchronized (this.singletonObjects) {
				// Consistent creation of early reference within full singleton lock
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							singletonObject = singletonFactory.getObject();
							this.earlySingletonObjects.put(beanName, singletonObject);
							this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}
}

示例

java 复制代码
@Slf4j
@Component
public class ExtendSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        log.info("predictBeanType run {}" ,beanName);
        return beanClass;
    }

    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        log.info("determineCandidateConstructors run {}" ,beanName);
        return null;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        log.info("getEarlyBeanReference run {}" ,beanName);
        return bean;
    }
}
相关推荐
Java小白笔记9 分钟前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
Zd0811 分钟前
14.其他流(下篇)
java·前端·数据库
小哇66614 分钟前
Spring Boot,在应用程序启动后执行某些 SQL 语句
数据库·spring boot·sql
千禧年@23 分钟前
微服务以及注册中心
java·运维·微服务
Xua305532 分钟前
浅谈Spring Cloud:认识微服务
spring·spring cloud·微服务
Joeysoda44 分钟前
Java数据结构 时间复杂度和空间复杂度
java·开发语言·jvm·数据结构·学习·算法
qq_290606271 小时前
tomcat,el表达式执行带参数命令,字符串数组,String[],el表达式注入
java·tomcat
18你磊哥1 小时前
java重点学习-JVM组成
java·开发语言·jvm
躺下睡觉~1 小时前
Unity-Transform类-父子关系
java·unity·游戏引擎
老王笔记1 小时前
Maven下载安装
maven