当前位置: 首页 > article >正文

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
DisposableBeandestroy

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

源码分析

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

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


@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

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

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

@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

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

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

/**
 * 返回以给定名称注册的(原始)单例对象。检查已实例化的单例,并允许对当前创建的单例进行早期引用(解决循环引用)。
 * @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;
	}
}

示例

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

在这里插入图片描述


http://www.kler.cn/news/304080.html

相关文章:

  • 通过策略模式实现对象创建工厂
  • QMainWindow,调用exec()实现QDialog阻塞效果
  • HTTPS和HTTP区别是什么?
  • 【Python机器学习】循环神经网络(RNN)——利用Keras实现循环神经网络
  • 【XR】AR HUD
  • 交换机vlan配置实现
  • Java、python、php三个版本 抗震救灾物资管理系统 抗洪救灾物资分配系统 救援物资申请平台(源码、调试、LW、开题、PPT)
  • Android Framework(四)WMS-窗口显示流程——窗口创建与添加
  • TON的两种地址
  • Linux环境下运行 KF-GINS(GNSS+IMU松组合) 详细步骤
  • CGAL中的网格
  • PL/SQL 继承Oracle Database 的可靠性、安全性和可移植性
  • 初始爬虫1(补充)
  • 某讯/企鹅滑块验证码逆向(一)
  • 阿里云专业翻译api对接
  • OpenXR Monado创建跨进程通信通道 ipc_connect
  • SpringBoot常见面试题
  • 【前端】 flex布局详解
  • JavaScript StartsWith()方法
  • 从用户数据到区块链:Facebook如何利用去中心化技术
  • Postgresql 删除数组中的元素
  • Linux系统使用Docker安装DockerUI并实现远程管理本地容器无需公网IP
  • Prompt最佳实践|善用分隔符,让你的Prompt更清晰
  • 解决VScode中每次git push或者pull都需要重新输入账户名和密码问题
  • PL/SQL Developer工具的使用
  • 【数据结构初阶】队列接口实现及用队列实现栈超详解
  • 基于SpringBoot的高校电动车租赁服务管理系统
  • 智能化等保测评工具的兴起与应用实践
  • 房产销售系统:SpringBoot技术优化方案
  • 在已安装Python环境的基础上安装anaconda或者其他版本Python