SpringloC容器的依赖注入源码解析(2)—— doGetBean之从缓存获取Bean(spring框架中依赖注入的三种方式)

SpringloC容器的依赖注入源码解析(2)—— doGetBean之从缓存获取Bean文章目录 直接打开AbstractBeanFactory的doGetBean方法:
protected T doGetBean(fin

文章目录

直接打开AbstractBeanFactory的doGetBean方法。

protected T doGetBean(final String name, @Nullable Final Class requiredType,

@Nullable 最终Object[] 参数,布尔值CheckOnly) 抛出BeansException {

//首先,将方法中传入的名称转换为容器的实际beanName。

//BeanName 以前有三种格式

//一个是原来的BeanName,一个是添加的BeanName,一个是别名

最终字符串beanName=transformedBeanName(name);

对象豆。

//经常检查单例缓存中是否有手动注册的单例。

对象共享实例=getSingleton(beanName);

//如果已经创建了单例bean的实例,且调用的getBean方法传递的参数为空,则执行处理逻辑。

//参数必须为空,因为它不能直接返回,因为它需要进一步赋值。

if (sharedInstance !=null args==null) {

如果(logger.isTraceEnabled()) {

//如果bean仍在创建中,则意味着循环引用

if (isSingletonCurrentlyInCreation(beanName)) {

logger.trace(“返回一个积极缓存的单例bean 实例\’” + beanName +

\’\’ 尚未完全初始化- 循环引用的结果。 ”);

}

除此之外{

logger.trace(\”返回单例bean 的缓存实例\’\” + beanName + \”\’\”);

}

}

//对于普通bean,直接返回。对于FactoryBeans,它返回getObject。

bean=getObjectForBeanInstance(sharedInstance, 名称, beanName, null);

}

除此之外{

//如果该bean 已经创建,则失败。实例:

//你可能处于循环引用中。

if (isPrototypeCurrentlyInCreation(beanName)) {

抛出一个新的BeanCurrentlyInCreationException(beanName)。

}

//检查该工厂是否存在bean 定义。

BeanFactory 父BeanFactory=getParentBeanFactory();

if (parentBeanFactory !=null !containsBeanDefinition(beanName)) {

//未找到- 检查父级。

String nameToLookup=原始BeanName(name);

if (AbstractBeanFactory 的父BeanFactory 实例) {

return ((AbstractBeanFactory)parentBeanFactory).doGetBean(

nameToLookup、requiredType、args、typeCheckOnly);

}

否则if (args!=null) {

//使用显式参数委托给父级。

return (T)parentBeanFactory.getBean(nameToLookup, args);

}

else if (requiredType !=null) {

//无参数- 委托给标准getBean 方法。

returnparentBeanFactory.getBean(nameToLookup, requiredType);

}

除此之外{

return (T)parentBeanFactory.getBean(nameToLookup);

}

}

如果(!typeCheckOnly){

markBeanAsCreated(BeanName);

}

尝试{

最终RootBeanDefinition mbd=getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);

//确保当前bean 所依赖的bean 的初始化。

String[] dependentOn=mbd.getDependsOn();

if (dependsOn !=null) {

for (String dep : dependentOn) {

if (isDependent(beanName, dep)) {

抛出新的BeanCreationException(mbd.getResourceDescription(), beanName,

\’\’ + beanName + \”\’ 和\’\” + dep + \”\’\” 之间的循环依赖);

}

registerDependentBean(dep, beanName);

尝试{

getBean(dep);

}

catch (NoSuchBeanDefinitionException ex) {

抛出新的BeanCreationException(mbd.getResourceDescription(), beanName,

\”\’\” + beanName + \”\’ 取决于缺少的bean \’\” + dep + \”\’\”。例子);

}

}

}

//创建一个bean 实例。

//如果BeanDefinition 是单例

如果(mbd.isSingleton()) {

//这里我们使用匿名内部类创建一个bean实例对象,并将其注册到依赖对象中。

SharedInstance=getSingleton(beanName, () – {

尝试{

返回createBean(beanName, mbd, args);

}

catch (BeansException ex) {

//显式地从单例中删除实例。 cache: 可能位于那里。

//创建过程急切地完成,以允许解决循环引用。

//还删除接收到临时引用的bean。

destroySingleton(beanName);

原件扔了。

}

});

bean=getObjectForBeanInstance(sharedInstance, 名称, beanName, mbd);

}

否则如果(mbd.isPrototype()) {

//这是一个原型- 创建一个新实例。

对象原型实例=null;

尝试{

beforePrototypeCreation(beanName);

原型实例=createBean(beanName, mbd, args);

}

最后{

afterPrototypeCreation(beanName);

}

bean=getObjectForBeanInstance(prototypeInstance, 名称, beanName, mbd);

}

除此之外{

字符串作用域名称=mbd.getScope();

最终范围scope=this.scopes.get(scopeName);

如果(范围==空){

抛出新的IllegalStateException(\”ScopeName \’\” +scopeName + \”\’\”);

}

尝试{

对象scopedInstance=scope.get(beanName, () – {

beforePrototypeCreation(beanName);

尝试{

返回createBean(beanName, mbd, args);

}

最后{

afterPrototypeCreation(beanName);

}

});

bean=getObjectForBeanInstance(scopedInstance, 名称, beanName, mbd);

}

catch (IllegalStateException ex) {

抛出新的BeanCreationException(beanName,

\’作用域\’\’+作用域名称+\’\’在当前线程中不活动。 \’ 请考虑+。

“如果从单例引用,则为此bean 定义一个作用域代理”,

原来的);

}

}

}

catch (BeansException ex) {

cleanupAfterBeanCreationFailure(beanName);

原件扔了。

}

}

//检查所需的类型是否与实际bean 实例的类型匹配。

if (requiredType!=null !requiredType.isInstance(bean)) {

尝试{

T ConvertedBean=getTypeConverter().convertIfNecessary(bean, requiredType);

if (convertedBean==null) {

抛出新的BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

返回一个ConvertedBean。

}

catch (TypeMismatchException ex) {

如果(logger.isTraceEnabled()) {

logger.trace(\”无法将Bean \’\” + name + \”\’ 转换为所需类型\’\” +

ClassUtils.getQualifiedName(requiredType) + \”\’\”, 示例);

}

抛出新的BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

}

返回(T)Bean;

}

第一行首先将方法中传递的名称转换为容器的实际beanName。回过头来看,beanName 可以通过三种格式获取。一种是原来的beanName,一种是添加的beanName,一种是别名。

最终字符串beanName=transformedBeanName(name);

对象豆。

输入转换后的BeanName方法

protected StringtransformedBeanName(字符串名称) {

返回canonicalName(BeanFactoryUtils.transformedBeanName(name));

}

公共静态StringtransformedBeanName(字符串名称){

Assert.notNull(name, \”\’name\’ 不能为null\”);

if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {

返回名称。

}

returntransformedBeanNameCache.computeIfAbsent(name, beanName – {

做{

beanName=beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());

}

while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));

返回beanName。

});

}

首先,它检查是否以前缀开头,如果不是,则全部删除。

接下来,输入canonicalName 方法。

公共字符串规范名称(字符串名称){

字符串规范名称=名称;

//处理别名.

字符串解析名称;

做{

//根据别名获取实际的beanName。如果我传递beanName,我什么也得不到。

solvedName=this.aliasMap.get(canonicalName);

if (resolvedName !=null) {

canonicalName=解析名称;

}

}

while (resolvedName!=null);

返回规范名称。

}

如果在地图中找到真实姓名,则证明传入的别名是别名。这时,为了避免成为别名的别名,就递归直到找不到为止。这就是真名。

返回doGetBean,获取BeanName 后,尝试缓存它并获取bean 实例。

对象共享实例=getSingleton(beanName);

请输入方法

公共对象getSingleton(String beanName) {

返回getSingleton(beanName, true)。

}

第二个参数控制是否允许非延迟加载。 true 表示允许立即加载。

protected Object getSingleton(String beanName, boolean allowedEarlyReference) {

//尝试从主缓存中检索完整的bean

对象singletonObject=this.singletonObjects.get(beanName);

//如果尚未创建完整的单例,则正在创建的bean 的名称将保存在singletonsCurrentlyInCreation 中。

//检查是否已经创建

if (singletonObject==null isSingletonCurrentlyInCreation(beanName)) {

//尝试锁定一级缓存对象,因为接下来将操作该缓存对象。

同步(this.singletonObjects){

//尝试从二级缓存中检索EarlySingletonObjects,该对象存储的是尚未添加的bean实例缓存。

singletonObject=this.earlySingletonObjects.get(beanName);

//如果没有检索到并且第二个参数为true,true表示允许对bean的循环引用。

if (singletonObject==nullallowEarlyReference) {

//尝试从三级缓存singletonFactories 中的ObjectFactory 实例的缓存中检索创建此bean 的单例工厂实例。

ObjectFactory?singletonFactory=this.singletonFactories.get(beanName);

//如果获得工厂实例

如果(singletonFactory!=null){

//调用单例工厂的getObject方法返回对象实例

singletonObject=singletonFactory.getObject();

//将实例放入二级缓存

this.earlySingletonObjects.put(beanName, singletonObject);

//从三级缓存中删除

this.singletonFactories.remove(beanName);

}

}

}

}

返回一个单例对象。

}

此方法位于DefaultSingletonBeanRegistry 类中,注册由容器创建的单例,并尝试从映射(singletonObjects) 中使用键BeanName 检索单例实例。这里,singletonObjects是一级缓存。

if (singletonObject==null isSingletonCurrentlyInCreation(beanName))

确保相关实例不是从一级缓存中检索的,并且必须是当前正在创建的实例。

公共布尔isSingletonCurrentlyInCreation(String beanName) {

返回this.singletonsCurrentlyInCreation.contains(beanName)。

}

isSingletonCurrentlyInCreation 方法查询该集合以查看BeanName 是否在正在创建的单例bean 列表中。如果bean是单例并且当前正在创建,则会向主缓存添加同步锁。然后对层缓存执行另外两个操作。

为了提高性能,二级缓存earlySingletonObjects和三级缓存singletonFactories都是HashMap。主缓存是安全的,因为它之前已被锁定。

首先,我们从二级缓存中检索一个bean 实例。

singletonObject=this.earlySingletonObjects.get(beanName);

二级缓存存储尚未实例化(填充)的bean。

稍后,我们将尝试从三级缓存singletonFactories 中检索。这里存储的是bean对应的ObjectFactory实例(工厂)。您可以稍后通过getObject() 属性创建该bean 的实例。 bean实例可能还没有被插入,所以先放入二级缓存,然后从三级缓存中清除(为了避免重复创建,三级缓存只有一层)我们要return non-injected beans(以确保bean实例被保存)(以确保bean实例被保存并且单例被销毁)是为了解决循环依赖的问题。

返回到doGetBean。

如果之前创建了单例bean的实例,并且调用的getBean方法传递的参数为空,则执行管理逻辑。它不能直接返回,因为它需要分配。

无论是否存在循环引用,您都必须调用getObjectForBeanInstance 来返回bean 实例。但是,由于您可能获得工厂而不是实例,因此从工厂创建bean 实例可能会多一个步骤。

受保护的对象getObjectForBeanInstance(

对象beanInstance,字符串名称,字符串beanName,@Nullable RootBeanDefinition mbd) {

//如果bean 不是工厂,则不要在调用代码中取消引用工厂。

if (BeanFactoryUtils.isFactoryDereference(名称)) {

if (nullBean beanInstance 实例) {

返回bean实例。

}

//如果名称开头但不是FactoryBean则直接抛出异常

if (!(FactoryBean 的beanInstance 实例)) {

抛出新的BeanIsNotAFactoryException(beanName, beanInstance.getClass());

}

if (mbd !=null) {

mbd.isFactoryBean=true;

}

返回bean实例。

}

//现在我们有一个bean 实例。这可以是常规Bean 或FactoryBean。

//对于FactoryBean,用它来创建bean

instance, unless the

// caller actually wants a reference to the factory.

// 如果是一个普通的Bean,则直接返回

if (!(beanInstance instanceof FactoryBean)) {

return beanInstance;

}

// FactoryBean创建出bean实例返回

Object object = null;

if (mbd != null) {

mbd.isFactoryBean = true;

}

else {

// 单例模式下,FactoryBean仅会创建一个Bean实例

// 因此需要优先从缓存获取,这里的缓存不是前面的三级缓存,这个是缓存工厂创建出来的bean的

object = getCachedObjectForFactoryBean(beanName);

}

if (object == null) {

// /若缓存没有则尝试创建

// Return bean instance from factory.

FactoryBean<?> factory = (FactoryBean<?>) beanInstance;

// Caches object obtained from FactoryBean if it is a singleton.

if (mbd == null && containsBeanDefinition(beanName)) {

mbd = getMergedLocalBeanDefinition(beanName);

}

boolean synthetic = (mbd != null && mbd.isSynthetic());

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

}

return object;

}

jvm里面通过Synthetic来标识是由自己的机制生成的类,用在这里标识这是Spring内部生成的Bean实例,不允许第三方改动。

进入到getObjectFromFactoryBean方法:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {

// 加果需要在工厂模式下维持单例的话

if (factory.isSingleton() && containsSingleton(beanName)) {

synchronized (getSingletonMutex()) {

// 又见双重检查锁机制,尝试再从缓存中获取,防止多线程下可能有别的线程已完成该单例Bean的创建

Object object = this.factoryBeanObjectCache.get(beanName);

if (object == null) {

// 调用工厂方法,创建Bean实例

object = doGetObjectFromFactoryBean(factory, beanName);

// Only post-process and store if not put there already during getObject() call above

// (e.g. because of circular reference processing triggered by custom getBean calls)

// 看看此时是否有别的线程先人一步创建好了Bean实例,如果是,则使用最先创建出来的以保证单例

// 之所以这样做是因为factoryBean是用户自定义的,就有可能是异步模式的,即getObject可能是异步的

Object alreadyThere = this.factoryBeanObjectCache.get(beanName);

if (alreadyThere != null) {

object = alreadyThere;

}

else {

// 如果是 Synthetic 的就不能使用后置处理器服务了

if (shouldPostProcess) {

// 该Bean实例是否已经有别的线程在尝试创建,但是还没有进行后置处理

if (isSingletonCurrentlyInCreation(beanName)) {

// Temporarily return non-post-processed object, not storing it yet…

return object;

}

// 后置处理完成前,先加入缓存里锁定起来

beforeSingletonCreation(beanName);

try {

// 触发BeanPostProcessor,第三方框架可以在此用AOP来包装Bean实例

object = postProcessObjectFromFactoryBean(object, beanName);

}

catch (Throwable ex) {

throw new BeanCreationException(beanName,

“Post-processing of FactoryBean’s singleton object failed”, ex);

}

finally {

// 创建完成后,从缓存锁定的名字里清除

afterSingletonCreation(beanName);

}

}

if (containsSingleton(beanName)) {

// 将其放入缓存,证明单例已经创建完成了

this.factoryBeanObjectCache.put(beanName, object);

}

}

}

return object;

}

}

else {

// 如果不是单例,则直接创建并返回

Object object = doGetObjectFromFactoryBean(factory, beanName);

if (shouldPostProcess) {

try {

object = postProcessObjectFromFactoryBean(object, beanName);

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, “Post-processing of FactoryBean’s object failed”, ex);

}

}

return object;

}

}

先确保factory创建出来的是单例,如果是就先上锁,这里用到了双重锁检查机制,尝试再去factoryBeanObjectCache缓存里获取一遍,防止多线程下可能有别的线程已完成该单例Bean的创建

回到doGetBean,if块里的代码执行完了之后就会跳过else的代码块,然后再经过一系列检查之后就返回bean实例了

最后

小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你需要这些资料,⬅专栏获取
else {

// 如果不是单例,则直接创建并返回

Object object = doGetObjectFromFactoryBean(factory, beanName);

if (shouldPostProcess) {

try {

object = postProcessObjectFromFactoryBean(object, beanName);

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, “Post-processing of FactoryBean’s object failed”, ex);

}

}

return object;

}

}

先确保factory创建出来的是单例,如果是就先上锁,这里用到了双重锁检查机制,尝试再去factoryBeanObjectCache缓存里获取一遍,防止多线程下可能有别的线程已完成该单例Bean的创建

回到doGetBean,if块里的代码执行完了之后就会跳过else的代码块,然后再经过一系列检查之后就返回bean实例了

最后

小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-afYjSJZt-1719529033761)]

[外链图片转存中…(img-SMoRBtmP-1719529033762)]

[外链图片转存中…(img-6THZw4k4-1719529033763)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你需要这些资料,⬅专栏获取

#以上关于SpringloC容器的依赖注入源码解析(2)—— doGetBean之从缓存获取Bean的相关内容来源网络仅供参考,相关信息请以官方公告为准!

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92672.html

(0)
CSDN的头像CSDN
上一篇 2024年6月28日
下一篇 2024年6月28日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注