getbean方法找不到bean_spring加载bean的过程

本文详细介绍了Spring框架在加载Bean时的整个过程,包括转换beanName、从缓存中加载单例、原型模式依赖检查、处理parentBeanFactory、转换GenericBeanDefinition为RootBeanDefinition、初始化依赖、根据不同scope创建bean以及进行类型转换等步骤。通过对getBean方法的逐步剖析,揭示了Spring如何管理和创建Bean的内部机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文基于spring-5.2.5

spring加载bean的大致过程如下:

(1)转换对应beanName;

(2)尝试从缓存中加载单例;

(3)原型模式的依赖检查;

(4)检测parentBeanFactory;

(5)将存储xml配置文件的GernericBeanDefinition转换成RootBeanDefinition;

(6)寻找依赖;

(7)针对不同的scope进行bean的创建;

(8)bean的类型转换;

下面从读取下图获取bean开始。

18fa91b8c538f005e6b16823e3fe56b9.png

点击进入getBean方法:

1d2449b4281ea86888826974f1d4da0c.png

进入到BeanFactory接口的getBean方法。该方法由它的实现类AbstractBeanFactory进行实现。AbstractBeanFactory类继承结构如下图:

bb6d43ce33e65aaf162bf18124a1491f.png

接下来我们进入到AbstractBeanFactory的getBean(String beanName)方法:

215f8be6d09f85b10a28fc27ed327bd8.png

接下来要进入正文了。

点击进入doGetBean(name, null, null, false)方法,首先第一行就是

d781e2aea6b978d474d56de0fb0ae4b6.png

该方法就是(1)转换对应的beanName.我们传入的name可能是别名,也可能是FactoryBean,所以需要进行一系列的解析。比如取指定的别名alias所表示的最终beanName,或者当传入的name="&car"时,会先去除&,而使得name="car"。

接下来就是(2)尝试从缓存中加载单例:

4616165f4c1af1209a5623f045407b2b.png

进入getSingleton方法:

84857ac50a965c69ae67b239e83fbd5a.png

单例在spring的同一个容易内只会被创建一次,后续再获取bean就直接从单例缓存中获取。其中的singletonFactorys用来存储beanName和创建bean的工厂之间的关系,也就是beanName-->ObjectFactory。在第一次创建原始bean时会添加相应的beanNme-->ObjectFactory关系。然后在循环依赖调用getSingleton(beanName)方法时可以通过获取相应的bean工厂,然后通过objectFactory获取bean,从而解决单例模式的循环依赖问题。

接下来进行(3)原型模式的依赖检查:

b59ae4bfa736155bad97c3df7b4fb2c2.png

目前spring只对单例模式通过setter方式注入构成的循环依赖进行了处理。因为spring容器不进行缓存"prototype"作用域的bean,因此无法提前暴露一个创建中的bean,所以原型模式的循环依赖无法处理,直接报异常。

接下来进行(4)parentFactory的检测。这个没什么可说的,如果parentFactory不为空并且当前加载xml文件所对应的Definition不存在,就只能通过parentFactory调用getBean方法获取bean了。

接下来就是将(5)存储配置文件的GernericDefinition转换成RootDefinition,因为bean所有的后续的处理都是针对于RootDefinition的。如果bean的父类不为空,则会合并父类的属性。

646485eb7cc593a7b7144edbcf09548b.png

因为在bean的初始过程中可能会用到其他的属性,并且可能是动态配置的,并且配置成依赖于其他的bean,所以在初始化一个bean时首先会(6)初始化这个bean所对应的依赖。

d688e5cd7a7401dd7a6d7b5e0db2cda9.png

这里对bean相关的依赖就行了注册,当这个bean被销毁之前会对相关注册的依赖缓存进行删除。并且初始化依赖的ben。

接下来就进入到了(7)根据不同scope进行bean的创建环节。这里主要分成了单例、原型和其他三种情况。因为我们在开发过程中主要用到的是单例,所以接下来只看单例模式好了。

8c62e1bcb2f9b1adff331191c82fe39b.png

这里的getSingleton方法是getSingleton(String beanName, ObjectFactory> singletonFactory)。是最开始的那个getSingleton方法的重载方法。这个方法的中beforeSingletonCreation(String beanName)中进行了this.singletonsCurrentlyInCreation.add(beanName)处理。也就使得最开始获取单例缓存时的条件判断isSingletonCurrentlyInCreation(beanName)为true。

我们进入createBean方法,然后直接跳转到AbstractAutowireCapableBeanFactory类的doCreateBean方法。这里面主要进行了如下处理:

1.实例化bean。主要获取通过BeanWrapper获取包装bean实例。

2.允许post-processors修改合并的bean Definition。

3.添加bean-->ObjectFactory关系缓存。

5f9323cc4bd64994ce699c3559730d83.png

4.初始化bean。

a9fee1f6eea2287e570239485bcd6f2d.png

包括对bean的属性注入以及对bean实现了相关Aware类以及初始化前,初始化时,初始化后的相关处理。

属性注入主要包括根据type进行注入和根据name进行注入。

a08597e0fe0dd4c76ec7107b4def56be.png初始化主要包括了如下的工作:

f1246495e9c7f52a767e9f034d4f2b27.png

比如:

当bean实现了BeanNameAware时,则调用BeanNameAware的setBeanName方法;

当bean实现了BeanClassLoaderAware时,则调用BeanClassLoaderAware的setBeanClassLoader方法;

当bean实现了BeanFactoryAware时,则调用BeanFactoryAware的setBeanFactory方法;

adcb330e9ce1feb9bb1c513d63d9594e.png

当bean实现了BeanPostProcessor时,调用BeanPostProcessor的postProcessBeforeInitialization方法;当bean实现了initializingBean,则调用initializingBean的afterPropertiesSet方法,假如自定义了init-method,则调用自定义的初始化方法;

当bean实现了BeanPostProcessor时,则调用BeanPostProcessor的postProcessAfterInitialization方法;

5.当bean配置了destroy bean的相关方法时,对该方法进行注册。

最后,有可能返回的bean的类型跟要求的类型不一致,那么就需要进行(8)类型转换了。

da679820ab396e8ac211db6f21a4c89c.png

以上就是所有的bean的加载过程,这个时候就可以返回我们需要的bean了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值