spring创建bean的生命周期,简单介绍一下spring bean的生命周期
目录
前言豆制品厂的继承体系豆的注册别名别名的注册总结
前言
上篇文章介绍了豆元信息的配置与解析过程,限于篇幅豆注册过程就没展开。
这里主要围绕bean定义读取器utils # registerbean定义展开分析下豆注册过程
公共静态void registerbean定义(bean定义持有者定义持有者,BeanDefinitionRegistry注册表)抛出bean定义存储异常{//在主名称下注册豆定义字符串bean名称=定义持有者。获取bean名称();注册表。registerbean定义(bean名称,定义持有者。getbean定义());//注册豆名称的别名(如果有)。string[]aliases=定义持有者。获取别名();如果(别名!=null) {for(字符串别名:别名){注册表。注册别名(bean名称,别名);}}}上面无论是注册弹底引信(底部引爆的缩写)还是建立别名-豆名之间的关系,均用到了BeanDefinitionRegistry,因此我们就以它为突破口来展开
BeanFactory的继承体系
对图中常用接口或类进行说明:
ListableBeanFactory集合类型豆制品厂提供一种可以查找所有豆实例的能力getBeanNamesForType(类)根据类型去查找豆名称列表不会强制Bean的初始化,可从源码中看出来getBeansOfType(类)根据类型去查找豆实例列表,http://www . Sina.com/getBeanNamesForAnnotation(类)根据注解类型获取豆名称列表getBeansWithAnnotation(类)根据注解类型获取豆实例列表findAnnotationOnBean(字符串,类)根据指定名称标注类型获取豆实例hierarchical([harkkl])beanfactory层次性豆制品厂,有父子容器的概念,可在可配置列表豆制品厂设置其父容器getParentBeanFactory()获取父容器布尔型包含本地Bean(字符串名称)在当前容器中查找是否存在该名称的豆实例SingletonBeanRegistry单实例豆制品厂,与单实例有关可配置豆制品厂可配置的豆制品厂,这个一般不用于应用程序,是给其他豆制品厂扩展用的。的确,定义了很多配置方法可配置列表豆制品厂可配置的集合类型的beanfactureyautowirecapablebeanfactory提供具有自动装配能力的豆制品厂透过继承体系可以看出,BeanDefinitionRegistry的实现类是DefaultListableBeanFactory,该类同时实现了诸多接口,可谓是豆制品厂中集大成者,因此我们到DefaultListableBeanFactory中阅读下弹底引信(底部引爆的缩写)注册及别名注册的源码
Bean的注册
先来分析下DefaultListableBeanFactory
的几个重要的成员属性
// 这个实质上就是IoC容器中Bean的载体,没错 它很重要,但它是无序的private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);//它代表了bd名称的集合,它是有序的 遵循bd注册的顺序private volatile List<String> beanDefinitionNames = new ArrayList<>(256);// 这是已创建bd名称的集合,在doGetBean方法根据beanName创建Bean时,beanName会被加到此集合中private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
上面两个属性都比较重要,两者结合使用的话可以实现bd的顺序访问(其实就是遍历beanDefinitionNames集合时,使用beanDefinitionMap去获取bd)
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {//对beanName、bd进行非空验证Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");//如果bd是AbstractBeanDefinition类型,则对bd进行验证(一般情况下 我们场景的bd都是继承自AbstractBeanDefinition的)if (beanDefinition instanceof AbstractBeanDefinition) {try { //bd验证((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {//省略异常代码}}//从beanDefinitionMap根据beanName取bdBeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);//如果beanName名称的bd已经存在if (existingDefinition != null) {//如果不允许Bean被重新注册 则抛出异常,这里默认值是trueif (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}//如果已被注册bd的角色值小于当前待注册bd的角色值 else if (existingDefinition.getRole() < beanDefinition.getRole()) {// 省略日志输出}//如果已注册的同名bd 与本次注册的bd不相同else if (!beanDefinition.equals(existingDefinition)) {//省略日志输出}else {//省略日志输出}//将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);}else {//流程走到这里 说明在beanDefinitionMap中不存在同名bd//条件成立 说明alreadyCreated不为空 即有bd已被创建if (hasBeanCreationStarted()) {// 如果在此之间 有bean正在被创建 则这里进行加锁处理synchronized (this.beanDefinitionMap) { //将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);//将beanName添加到beanDefinitionNames集合中List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;//如果beanName是手动注册的单例Bean名称,则更新manualSingletonNamesif (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);//这里从集合中删除的原因个人理解://manualSingletonNames记录的是在registerSingleton时被添加的单实例beanName,而这里注入的不是单实例Bean。因为manualSingletonNames包含了此beanName,因此需要剔除updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;}}}else {//如果没有bean在被创建//将beanName-bd键值对放入beanDefinitionMap集合this.beanDefinitionMap.put(beanName, beanDefinition);//将beanName添加到集合中this.beanDefinitionNames.add(beanName);//这里从manualSingletonNames中剔除,个人理解为拖地操作,毕竟若集合中没有此beanName 也remove不了this.manualSingletonNames.remove(beanName);}//这个集合表示冻结配置时缓存的beanName集合,暂时未理解透此集合的用途this.frozenBeanDefinitionNames = null;}//如果已存在同名bd或已存在同名的单例对象,则重置所有已被缓存的同名的bd数据,因此这里bd注册成功后,肯定后续还会再生成Bean的if (existingDefinition != null containsSingleton(beanName)) {resetBeanDefinition(beanName);}}
其实分析下来发现Bean注册的过程还是比较容易理解的,下面试着总结一下:
若bd未被注册过,则将bd信息存入BeanDefinitionMap等集合中若bd已被注册过,允许覆盖注册的情况下,将bd信息存入BeanDefinitionMap等集合中,并清除已被缓存的同名bd信息下面看一下清除bd信息的代码逻辑
protected void resetBeanDefinition(String beanName) {// 如果此bd属于被合并的BeanDefinition,则这里将其从MergeBeanDefinition集合中剔除clearMergedBeanDefinition(beanName);// 如果已存在同名的单例对象 则销毁,具体细节先不展开destroySingleton(beanName);// 这里for循环逻辑与MergeBeanDefinition相关,如果存在MergedBeanDefinitionPostProcessor,则重置此bdfor (BeanPostProcessor processor : getBeanPostProcessors()) {if (processor instanceof MergedBeanDefinitionPostProcessor) {((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);}}// BeanDefinition运行有层级的,如果此bd拥有多个父级bd,那么这里递归地重置其父bdfor (String bdName : this.beanDefinitionNames) {if (!beanName.equals(bdName)) {BeanDefinition bd = this.beanDefinitionMap.get(bdName);if (beanName.equals(bd.getParentName())) {resetBeanDefinition(bdName);}}}}
alias别名的注册
看了Bean的注册,再来看别名的注册 发现流程比较清晰,基本上一目了然。
//注意 这里的name 不要具象为beanName,虽然我们是从建立beanName--alias关系出发追溯到这里的public void registerAlias(String name, String alias) {//对name、alias进行断言验证Assert.hasText(name, "name must not be empty");Assert.hasText(alias, "alias must not be empty");synchronized (this.aliasMap) {//如果别名与beanName相同,那别名就没有必要存在了,因此选择直接从this.aliasMap中移除此别名if (alias.equals(name)) {this.aliasMap.remove(alias);//省略日志输出}else { //从aliasMap中根据别名获取nameString registeredName = this.aliasMap.get(alias);if (registeredName != null) { //如果已存在的registeredName与此此要注册的name一致,那就没必要注册了if (registeredName.equals(name)) {return;}//流程走到这里,说明同一个别名,对应两个name,如果不允许alias覆盖 则抛出异常if (!allowAliasOverriding()) {//省略异常及日志输出}//这里对alias进行循环检查,避免出现A的别名是B,B的别名是A的情况checkForAliasCircle(name, alias);//将alias--name 放入aliasMapthis.aliasMap.put(alias, name);//省略日志输出}}}
alias与beanName的映射关系,为根据名称查找Bean又提供了一种思路。就是说除了根据beanName外,也可以根据alias去查找Bean。
这部分源码如下
//name可以是beanName,也可以是aliaspublic String canonicalName(String name) {//局部变量赋值String canonicalName = name;// Handle aliasing...String resolvedName;do { //如果从aliasMap中能根据alias分析出beanNameresolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);// 无论入参name是beanName还是alias,这里返回的都应该是beanName了return canonicalName;}
总结
好了,这篇主要分析了BeanDefinition的注册,顺带着也说了别名的注册情况。既然BeanDefinition已经注册完成,那紧接着就是BeanDefinition的实例化过程了,这个放到下次分析吧。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注盛行IT的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。