单例Bean的创建流程
创始人
2024-06-03 12:29:38
0

简要介绍

bean的创建,需要经过查找,创建,注入,实例化三阶段

finishBeanFactoryInitialization

前言提到,refresh方法执行了finishBeanFactoryInitialization,这个方法便是完成了bean的创建与初始化。
每一个最后都会走向doGetBean

doGetBean

doGetBean是用于返回bean的方法,如果bean不存在,还会调用其内部的doCreateBean完成bean的创建

protected  T doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = transformedBeanName(name);Object bean;// 从缓存池中获取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 + "'");}}//这是为了防止beanFactory套用beanFactory,这里提供了递归使用getObject方法,从而获取最终beanbean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// 空的,要不是没创建过的单例bean,要不是原型bean,并且这个bean一定不能是if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 打上已经创建的标记,防止对象反复创建if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// 优先完成@DependOn注解指定的类的bean的创建与获取String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 这里面实际上就是增加这个bean依赖了哪个bean,和哪个被依赖的bean被这个bean依赖的双重引用registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// 如果是单例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;}});// 也是递归向里调用,直到返回的不是factoryBeanbean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// 检查一下是否需要格式转换,比如XML的字符串转化为对象的类型if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;
}

试图直接返回

这是singletonObject的逻辑,如果一级有,直接返回,如果一级没有,那么就可能涉及修改操作,所以提前完成上锁。为什么锁的是一级缓存而不是二级缓存呢,正是因为三级缓存在完成调用之后会将对象加入二级缓存,然后其它有着相同需求正在等待的线程就可以直接从二级缓存取出对象,而不需要双重检验机制了。
然后进行二级和三级缓存的查找。如果是在三级缓存中找到的,那么就会调用其中getObject方法,这个方法在单例中就是getReference方法

//三级缓存,保存工厂
private final Map> singletonFactories = new HashMap<>(16);
//二级缓存,保存工厂创建的对象
private final Map earlySingletonObjects = new HashMap<>(16);
//一级缓存,保存所有完成创建的对象
private final Map singletonObjects = new ConcurrentHashMap<>(256);protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

doCreateBean方法的“AOP”

以下对源码的验证部分进行大量删除,只剩下主干
这个方法在调用doCreateBean之前,会将其加入一个set表示正在创建,在调用doCreateBean正常结束之后会将其删除,并完成一级缓存的添加和二三级缓存的清除

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// 添加进入singletonsCurrentlyInCreation,表示是正在创建的单例对象beforeSingletonCreation(beanName);boolean newSingleton = false;try {//这里才是真正调用了 doCreateBeansingletonObject = singletonFactory.getObject();// 如果走到这里说明初始化成功了newSingleton = true;} finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}// 从singletonsCurrentlyInCreation中移除afterSingletonCreation(beanName);}// 如果初始化成功了,那么加入一级缓存if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}
}protected void addSingleton(String beanName, Object singletonObject) {// 将这个对象加入一级缓存,从二三级删除,并标记为已经注册synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}

doCreateBean的实体

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}// 实例化beanif (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 可以理解为走了一个beanPostProcessorssynchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);mbd.postProcessed = true;}}// 如果设置了属性,并且是正在创建的单例bean,就会添加单例工厂.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;// 注入属性populateBean(beanName, mbd, instanceWrapper);// 初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);// 如果支持循环引用,并且存在该对象,这是为了保证返回的一定是代理对象if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}}// 如果需要回调destory方法,会放入destroybeans,这样在销毁的时候就会从destroybeans剔除并回调registerDisposableBeanIfNecessary(beanName, bean, mbd);return exposedObject;
}

关联的属性这时候注入

属性注入的时候对Autowire注解进行了注入

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 使用AutowiredAnnotationBeanPostProcessor,将类中所有Autowired注解都提取出来,并在postProcessPropertyValues逐一完成注入for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}// 把property数组放入beanWrapper里面,便于后续使用if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}

对于三级缓存的解释

比如A包含B,B包含A的关系,用户尝试获取A。
一开始进入A的getBean,由于缓存中不存在A,所以进入A的create方法,会生成单例工厂,并将单例工厂放入三级缓存,然后进入属性注入环节,会尝试注入B,这时陷入B的getBean。
B会标记自己是正在生成,然后进入create方法,生成单例工厂,并将单例工厂放入三级缓存,然后进入属性注入环节,会尝试注入A,这时陷入A的getBean,这时会从三级缓存中取出A的单例工厂,并且调用其getEarlyReference方法,AbstractAutoProxyCreator会将A加入AOP缓存,然后生成代理对象,并将A移出三级缓存,将其注入二级缓存,然后返回给B使用。B获取到之后会继续完成属性注入和初始化代理,然后从三级缓存中删除自己,加入一级缓存,返回代理对象B给A。
A拿到了B的代理对象,会继续完成属性注入和初始化代理,在初始化代理时候,A会检查AOP缓存,由于A会在AOP缓存里发现自己,所以直接返回。在create方法的最后,A会从二级缓存中取出A的代理,然后从二级缓存中删除A,并加入一级缓存,将A的代理返回给用户。
假设更麻烦一些,B在获取A的时候,C也在获取A,会怎样呢。由于进入二级和三级缓存都有同一把锁,比如B先进入了这把锁,那么它会先检查二级缓存是否有A,发现没有,会进入三级缓存取出A的工厂,通过A的工厂完成A的代理,再将其放入二级缓存,然后释放锁,这是C才会获取到这把锁,它会在二级缓存直接发现了A,于是直接注入,这就是二级缓存的作用。

相关内容

热门资讯

我来教大家“掼蛋大师辅助器ap... 亲,掼蛋大师这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,掼蛋大师的开挂软件,名...
我来教大家“开心联盟辅助器ap... 您好,开心联盟这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打...
我来教大家“友愉棋牌辅助器ap... 您好,友愉棋牌这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打...
我来教大家“全盛棋牌辅助器ap... 亲,全盛棋牌这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,全盛棋牌的开挂软件,名...
我来教大家“情怀三三麻将辅助器... 我来教大家“情怀三三麻将辅助器app官方下载最新版本更新”详细分享开挂一、情怀三三麻将AI软件牌型概...
我来教大家“无锡好运麻将辅助器... 亲,无锡好运麻将这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,无锡好运麻将的开挂...
我来教大家“推筒子辅助器app... 您好,推筒子这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打牌...
我来教大家“比奇堡辅助器app... 我来教大家“比奇堡辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方神...
我来教大家“新兴茶苑辅助器ap... 我来教大家“新兴茶苑辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方...
我来教大家“欢乐互动辅助器ap... 我来教大家“欢乐互动辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方...
我来教大家“东方互娱辅助器ap... 亲,东方互娱这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,东方互娱的开挂软件,名...
我来教大家“天天乐清麻将辅助器... 我来教大家“天天乐清麻将辅助器app官方下载最新版本更新”详细分享开挂一、天天乐清麻将AI软件牌型概...
我来教大家“唐三彩辅助器app... 我来教大家“唐三彩辅助器app官方下载最新版本更新”详细分享开挂一、唐三彩AI软件牌型概率发牌机制”...
我来教大家“Y0辅助器app官... 我来教大家“Y0辅助器app官方下载最新版本更新”详细分享开挂一、Y0AI软件牌型概率发牌机制”必胜...
我来教大家“天天互娱辅助器ap... 亲,天天互娱这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,天天互娱的开挂软件,名...
我来教大家“悟空竞技麻将辅助器... 亲,悟空竞技麻将这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,悟空竞技麻将的开挂...
我来教大家“情怀开化麻将辅助器... 我来教大家“情怀开化麻将辅助器app官方下载最新版本更新”详细分享开挂一、情怀开化麻将AI软件牌型概...
我来教大家“龙炎互娱辅助器ap... 我来教大家“龙炎互娱辅助器app官方下载最新版本更新”详细分享开挂一、龙炎互娱AI软件牌型概率发牌机...
我来教大家“闲逸碰胡辅助器ap... 亲,闲逸碰胡这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,闲逸碰胡的开挂软件,名...
我来教大家“友聚麻将辅助器ap... 我来教大家“友聚麻将辅助器app官方下载最新版本更新”详细分享开挂一、友聚麻将AI软件牌型概率发牌机...