Spring源码探析之IOC

一.源码的简单设计思想:

对象谁创建的?->Spring容器

对象如何创建?

Spring是随随便便创建对象吗?不是

这就是BeanDefinition

在解析xml文件或解析注解时,方式肯定是不一样的,能不能给出一个抽象层?这便是读取器

当我们容器有这些bean定义信息,紧接着就可以做bean的对象实例化

当一个对象创建完成后,它经历了几个过程?一般我们描述中直接就说实例化,但实际包含两个步骤

在bean定义信息到BeanFactory的中间是不是可以有一个类似拦截器的东西,我可以把这些bean定义信息拦截下来从而可以进行修改,当然这里它不叫做拦截器,而是后置处理器 BeanFactoryPostProcessor,而且不止一个。

Bean的生命周期:

如果当前这个对象想获取到当前容器的某些属性值的时候,就需要实现这些aware接口。

 

另外再提一点,Bean实例化完成后,我要做一些事;Bean初始化完成后,我要做一些事。。。这样怎样实现?

二.一头扎进源码的海洋

从经典的refresh()开始:

根据上面所说,如果我们来写源码,第一步应该先做什么?读取配置文件。但是读取配置文件需要先有BeanFactory,没有容器,读取了也没地方放啊。

1.创建BeanFactory

顺便提下这里的prepareRefresh()只是些前戏准备。

2.加载bean定义信息

AbstractRefreshableApplicationContext#loadBeanDefinitions有AbstractXmlApplicationContext和XmlWebApplicationContext实现,这两个类都是AbstractRefreshableWebApplicationContext的子类。先看AbstractXmlApplicationContext的实现。

先创建一个XmlBeanDefinition读取器。

一个是获取资源,一个是获取定位。看下定位不为空之后执行的方法。

ResourceLoader用来加载资源的,将定位信息转为资源信息。如果是resource就没有这一步骤。下面有个分支,是否可以解析。

一定可以解析,因为:

当前上下文是ResourcePatternResolver的实例。

最终绕一圈还是回到直接加载资源的方法。

用Set来防止重复加载Resource。

Document是通过JDK自带的DocumentBuilder机械InputSource得到的。

解析默认的元素标签,如<beans/>,<bean />,<import />,<alias />,每一种标签都有对应的方法。

BeanDefinitionRegistry是与保存bean定义信息有关的接口,对bean定义信息的增删改查就是通过该接口。

最终将bean定义信息存在ConcurrentHashMap中,key为beanName。

最后发布注册完成事件。

 

prepareBeanFactory() 主要是准备了spring提供的bean增强工具。

 

3.执行BeanFactoryPostProcessor

先对beanFactory做一些准备工作,set一些属性。

postProcessBeanFactory(beanFactory)留给子类进行扩展工作的。

invokeBeanFactoryPostProcessors()

执行所有已注册的BeanFactoryPostProcessors 

为什么必须要在实例化前调用? 因为对工厂增强的很多的东西都是为了实例化bean用的。

对BeanFactoryPostProcessor进行分类,通过registryProcessor.postProcessBeanDefinitionRegistry(registry)进行回调,完成注册。如果不是BeanDefinitionRegistryPostProcessor,继续分类。

(1)通过beanFactory.getBeanNameForType,以空间换时间。

接着对currentRegistryProcessor进行排序。

invokeBeanDefinitionRegistryPostProcessors()

排好序了,便逐个调用。

用完就清空。

上面是优先级较高的 PriorityOrdered, 接着是 ordered,过程一致。

这里其实可以优化,多一个list即可,为什么要遍历两遍呢?

最后 处理其他的 BeanDefinitionRegistryPostProcessors

最后调用postProcessBeanFactory

接着看registerBeanPostProcessors(),注册BeanPostProcessors,其方法逻辑和invokeBeanFactoryPostProcessors()大致相同。BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,执行初始化方法前后,允许开发者对 bean 实例进行修改。

这里可以顺便提一下,

@AutoWired起作用依赖AutowiredAnnotationBeanPostProcessor,@Resource依赖CommonAnnotationBeanPostProcessor,这俩都是BeanPostProcessor的实现。

  • 与invokeBeanFactoryPostProcessors 不同的是,invokeBeanFactoryPostProcessors 方法会直接调用 BeanFactoryPostProcessor 实现类的方法,而 registerBeanPostProcessors 方法只是将 BeanPostProcessor 实现类注册到 BeanFactory 的 beanPostProcessors 缓存中。这是因为,此时还未到 BeanPostProcessor 实现类“出场的时候”。
  • BeanPostProcessor 实现类具体的 “出场时机” 在创建 bean 实例时,执行初始化方法前后。postProcessBeforeInitialization 方法在执行初始化方法前被调用,postProcessAfterInitialization 方法在执行初始化方法后被调用。
  • BeanPostProcessor 实现类和 BeanFactoryPostProcessor 实现类一样,也可以通过实现 PriorityOrdered、Ordered 接口来调整自己的优先级。

4.调用反射机制进行bean的实例化

先注册BeanPostProcessors,只是注册没有执行。

initMessageSource进行国际化。

initApplicationEventMulticaster()初始化事件多播器,提前将事件发布器准备好。

onRefresh()留给子类扩展实现。

registerListeners() 注册事件监听器。以上都是做些实例化的准备工作。

紧接着就开始实例化过程了,

设置转换器。

直接到最后一行

遍历所有的bean定义信息,先判断当前bean对象是否是抽象的,是否是单例的,是否是懒加载的。

再判断当前bean对象是否实现了FactoryBean接口。没有实现,则直接跳到getBean();

以do开头都是核心方法

用实例包装类接收创建bean实例

 

使用简单的无参构造器

到达终点,实例化最底层

createBeanInstance只是在堆里开辟了一段空间,还没有完成对属性的赋值。

属性填充

5.执行BeanPostProcessors

属性填充后继续往下走,先调用实现了aware接口的方法。

接着执行BeanPostProcessor的postProcessBeforeInitialization()

接着执行我们自定义的init-method方法。

最后执行BeanPostProcessor的postProcessAfterInitialization()

6.执行finishRefresh()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值