博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring IoC源码解读——谈谈bean的几种状态
阅读量:6658 次
发布时间:2019-06-25

本文共 5677 字,大约阅读时间需要 18 分钟。

阅读Spring IoC部分源码有一段时间了,经过不断的单步调试和参阅资料,对Spring容器中bean管理有了一定的了解。这里从bean的几个状态的角度出发,研究下IoC容器。

一、原材料

  Xml中的bean定义配置(或者注解)、及Java代码

public class Book implements InitializingBean, DisposableBean, BeanFactoryAware, ApplicationContextAware{    private String title;        public Book(){        System.out.println("调用了Book默认构造函数");    }        public void productBook(){        System.out.println("书本初始化init-method");    }  ///.......}

 

二、半成品

  BeanDefinition是Spring中很重要的一个接口,作用是对bean的一种抽象(简单的理解是他的属性对应了<bean>中定义的属性和子节点等信息)。他是半成品,所以我们几乎不会直接使用,而是在IoC容器内部流通!

阅读源码发现是用SAX解析xml,然后保存到BeanDefinition对象。以下是关键的伪代码

/***BeanDefinitionParserDelegate.java*/public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {    AbstractBeanDefinition bd = createBeanDefinition(className, parent){      GenericBeanDefinition bd = new GenericBeanDefinition();      bd.setBeanClassName(className);      return bd;         }    parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);    parseConstructorArgElements(ele, bd);    parsePropertyElements(ele, bd);  //省略了解析其他子节点的代码}

核心的解析过程比较简单,创建了GenericBeanDefinition,然后节点属性和<property>、<construct-arg>等设置为他的属性。

那么,还有一个比较关键的步奏,就是转化后的BeanDefinition存放的时机和位置,是在Spring IoC容器启动时存放的,具体代码:

/***DefaultListableBeanFactory.java*/    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){        synchronized (this.beanDefinitionMap) {            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);            if (oldBeanDefinition != null) {                if (!this.allowBeanDefinitionOverriding) {                    throw new BeanDefinitionStoreException("Cannot register bean definition  for bean , There is already bound.");                }                else {                    this.logger.info("Overriding bean definition for bean, replacing oldBeanDefinition");                }            }            else {                this.beanDefinitionNames.add(beanName);            }            this.beanDefinitionMap.put(beanName, beanDefinition);        }}

可以看到最终存储到了beanDefinitionMap这个Map中,来看看他的定义(DefaultListableBeanFactory.java中)

private final Map
beanDefinitionMap = new ConcurrentHashMap
(64);

这样,Spring容器就持有了BeanDefinition。

 

三、成品

获取成品就是获取具体的bean对象,其实就是Object bean = BeanFactroy.getBean(beanName).这里根据scope的不同,会有一些不同,简而言之:

A、singleton在IoC容器初始化时实例化,并缓存到Map中;getBean(singletonBeanName)时从这个Map中取即可;

  如果singleton同时lazy-init="true",第一次getBean时缓存到Map,以后从Map中取;

B、getBean(prototypeBeanName)时每次都实例化新的bean对象;

 

1、singleton的bean

  直接看伪代码(截取了部分关键代码)

//从getBean入手    BeanFactroy.getBean("beanName"){        AbstractBeanFactory.createBean{            Object beanInstance = doCreateBean(beanName, mbd, args){                // Eagerly check singleton cache for manually registered singletons.                //这是返回了缓存的singleton的bean:com.sky.vo.Book@1a1ecd                Object sharedInstance = getSingleton(beanName){                    return Object singletonObject = this.singletonObjects.get(beanName);                }                return (T)bean;            }            }    }

从源码我们可以看到,对于singleton的bean,我们直接从singletonObjects这个Map中取!

public class DefaultSingletonBeanRegistry{  /**缓存了singleton的bean:beanName--->bean实例*/  private final Map
singletonObjects = new ConcurrentHashMap
(64);}

那么bean实例是什么时候存入到这个map的呢?看源码知道是在IoC容器启动时。

通过多次分析源码,我们知道AbstractApplicationContext.refresh()完成了容器的初始化过程,singleton的bean的实例化也是在这完成的。

public void AbstractApplicationContext.refresh(){        //创建Spring容器        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();                // Instantiate all remaining (non-lazy-init) singletons.        AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory){            DefaultListableBeanFactory.preInstantiateSingletons(){                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {                    //然后,执行了getBean的操作!!!这里执行的代码就是BeanFactory.getBean(beanName)部分                    AbstractBeanFactory.getBean(beanName){                        AbstractBeanFactory.doGetBean(beanName){                            //缓存为空                            Object sharedInstance = getSingleton(beanName);                            //如果是singleton                            if (mbd.isSingleton()) {                                DefaultSingletonBeanRegistry.getSingleton(){                                    synchronized (this.singletonObjects) {                                        //这里缓存也是空的                                        Object singletonObject = this.singletonObjects.get(beanName);                                        //实例化bean                                        singletonObject = singletonFactory.getObject(){                                            Object beanInstance = doCreateBean(beanName, mbd, args);                                        }                                        //这里非常重要,把实例化的bean放到map中                                        addSingleton(beanName, singletonObject){                                            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));                                        }                                    }                                }                            }                        }                    }                }            }        }    }

截取了部分关键的代码片段,可以看到Spring容器初始化时会把实例化的singleton的bean放到singletonObject

 

转载于:https://www.cnblogs.com/postnull/p/4980020.html

你可能感兴趣的文章
vivado 波形保存以及arp
查看>>
下拉框里根据选择项不同,显示的图片也不同
查看>>
回顾:Linux环境 Mysql新建用户和数据库并授权
查看>>
第四周作业
查看>>
Android平台Native代码的崩溃捕获机制及实现
查看>>
saltstack之(九)配置管理源码部署Nginx
查看>>
2017年Android SDK下载安装及配置教程(附带原文地址)
查看>>
Cocos2dx 入门小游戏实例
查看>>
HDU——2067 小兔的棋盘
查看>>
洛谷——P1560 [USACO5.2]蜗牛的旅行Snail Trails
查看>>
py标准模块总结
查看>>
了解的应用领域 程序语言的岗位
查看>>
ajax
查看>>
iOS Development Sites
查看>>
2018-2019-1 20165320 《信息安全系统设计基础》第四周学习总结
查看>>
Church 整数前驱的推导
查看>>
git push之后回滚(撤销)代码
查看>>
暑假练习赛 006 E Vanya and Label(数学)
查看>>
Toxophily
查看>>
C# 中的委托和事件(转)
查看>>