0%

spring源码学习(一)

Spring源码学习之IoC(走马观花)

什么是IoC

  • 调用方不去new被调用方,而是由第三方去new

IoC和DI的区别

首先,给出结论:IOC是目的,DI是手段

如何理解这个结论呢?

  • 引用Martin Fowler原话
1
As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussionwith various IoC advocates we settled on the name Dependency Injection.

大意是

1
已经存在某种模式,该模式被称为IoC,但IoC太普遍,会让人产生疑惑,为了让表意更明确,决定用DI来精确指称那个模式。

IoC要做的事情就是让控制反转,对象实例不再由程序员来new,这是它的目的,而IoC主要的实现方式有两种:依赖查找,依赖注入。

DI即Dependency Injection就是依赖注入,它只是IoC这个目的的一种实现手段,只是因为依赖注入相对于依赖查找是一种更可取的手段,使得它成了更流行的那一种,所以才导致人们总是把IoC和DI混为一谈。

Bean是如何被初始化的

  • 首先编写一个简易demo,方便我们快速的找到IoC所做的事情

spring-ioc-1

  • 从图中我们可以知道,ClassPathXmlApplicationContext是实例化Bean的关键,它把Bean加载到context,并通过getBean方法拿到Bean实例。那我们接着看看ClassPathXmlApplicationContext到底做了什么

    spring-ioc-2

  • 首先来看一下它的类图,大概了解一下其大致框架

  • ClassPathXmlApplicationContext的构造函数看,最核心的就是refresh()函数,其他只是设一些值。
    而这个refresh()是调用父类AbstractApplicationContext中的refresh()
    根据它的注解可知它是加载刷新了整个context,并且加载所有Bean定义和创建对应的单例。

spring-ioc-refresh-1

那我们来看一下这个refresh函数做了什么

spring-ioc-refresh-2

里面有许多对于beanFactory的操作方法,重点看下obtainFreshBeanFactory()(重新获取一个BeanFactory)。

它里面有个核心的方法refreshBeanFactory()

spring-ioc-refreshBeanFactory

如果已有BeanFactory,先删除所有Bean,然后关闭BeanFactory。
然后创建一个新的ListableBeanFactory,这个工厂里会预先加载所有的Bean。
最后核心的就是loadBeanDefinitions(beanFactory)

spring-ioc-load-1

它是加载Bean的定义,实现交给了下面这个方法

spring-ioc-load-1

用的是XmlBeanDefinitionReader直接读配置文件加载Bean Definition(Bean定义)到BeanFactory。它里面一步步把xml的配置文件拆解读取,把一个个Bean Definition加载到BeanFactory里。

至此,已经有用一个加载好Bean Definition的BeanFactory了。
其他方法也是围绕BeanFactory后置处理和Context的配置准备。

Bean又是如何被获取的

找到一开始的context.getBean(),查看源码找到对应的DefaultListableBeanFactory中的实现

spring-ioc-getBean-1

可以看出 拿到Bean的关键在于resolveBean方法,再次深入查看其源码

spring-ioc-resolveBean

如果namedBean不为空,直接从其中获取到实例返回,如果为空则获取父类的,那么我们再进到resolveNamedBean中看看

spring-ioc-resolveNamedBean

这里通过getBeanNamesForType获取到当前Type下所有BeanName,看看spring是如何做的

spring-ioc-getBeanNamesForType

两个return最终都是调用了doGetBeanNamesForType,继续往里看

spring-ioc-doGetBeanNamesForType

可以看到,它是遍历BeanFactory里面维护的beanDefinitionNames和manualSingletonNames成员变量,找出命中的beanName返回。(方法很长,截图未能展示manualSingletonNames部分)

然后拿着这个beanName去找具体的bean实例。这里的代码比较长,在AbstractBeanFactory里面的doGetBean()中实现。

spring-ioc-doGetBean

大意是先尝试去找手动添加bean的单例工厂里找有没有对应的实例,没有的话就往父类beanFactory里面找,最后没有的话就生成一个。

总结

  • 本文只是走马观花的了解IoC的大致过程,知道其中调用了哪些类等等
  • 重点需要了解BeanFactory中的DefaultListableBeanFactory实现,在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的。包含了基本IoC容器所具有的重要功能。
  • 知道了大致过程后接下来应该仔细阅读,了解其中所运用的设计模式,以及各个类在整个架构中担任了什么功能