spring技术内幕 - omigaw/spring- GitHub Wiki

Spring框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分。

  • Data Access/Integration: JDBC、ORM、OXM、JMS、Transactions
  • Web(MVC/Remoting):Web、Servlet、Portlet、Struts
  • AOP:Aspects、Instrumentation
  • Core Container:Beans、Core、Context、Expression Language
  • Test:整合Junit

一、IOC和DI

IOC:控制反转,是Spring的核心。控制反转指的是将对象的创建交给Spring容器管理,这样做一方面有利于代码解耦,另一方面便于对bean的生命周期统一管理,也就是提取bean的一些共有属性:前置处理函数、后置处理函数、销毁等进行封装。
DI:依赖注入。依赖注入是控制反转的实现方式,通过依赖注入给bean对象添加依赖的各种属性。

二、Spring的IOC容器设计

Spring中有两个系列的容器:1.实现BeanFactory接口的简单IOC容器,这些容器提供了IOC容器的基本功能。2.实现ApplicationContext接口的应用上下文,这些应用上下文不仅提供了IOC容器的基本功能,而且提供了一些高级功能,是IOC容器的高级形式。

1.BeanFactory 系列容器接口

BeanFacotory是IOC容器最顶层的接口,定义了IOC容器的基本规范。Beanfactory共有三个直接的子接口:
* ListableBeanFactory:Bean是可列表化的。
* HierarchicalBeanFactory:Bean是有继承关系的,可以管理父IOC容器。
* AutowireCapableBeanFactory:Bean是自动装配的。
BeanFactory接口定义了IOC容器最基本的形式,DefaultListableBeanFactory、XmlBeanFactory等是基本IOC容器的具体实现。

2.ApplicationContext系列容器接口

ApplicationContext作为一系列重要的容器产品,一方面继承了BeanFactory基本的IOC容器功能;另一方面,对BeanFactory进行了功能扩展。ApplicatonContext继承了一系列接口,为基本的IOC容器扩展了高级的容器特性,例如:
* ApplicationEventPublisher:支持应用事件
* MessageSource:支持国际化信息源
* ResourcePatternResolver:允许以路径模式定位Resource
* EnvironmentCapable:应用上下文环境检查

FileSystemXmlApplicationContext和ClassPathXmlApplicationContext是常用的应用上下文,二者分别实现了从文件系统和类路径读取以XML格式定义的BeanDefinition的功能

三、IOC容器初始化 —— Resource定位

在使用IOC容器之前,需要定义一个Resource来定位容器BeanDefinition的资源文件,以FileSystemXmlApplicationContext为例,ApplicationContext的Resource定位过程为:

  • refresh
  • obtaionFreshBeanFactory
  • refreshBeanFactory
  • loadBeanDefinitions
  • getResources
  • getResource

四、IOC容器初始化 —— BeanDefinition载入

BeanDefinition的载入可以分为两个过程:首先,通过documentLoader获取得到Document对象;然后,根据Spring Bean的规则解析Documnet得到BeanDefinition。

1.获取Document

2.解析Document

五、IOC容器初始化 —— BeanDefinition注册

通过Map持有BeanDefinition,BeanDefinition就在IOC容器中建立了相应的数据结构,但这些BeanDefinition还是相互独立的,还需要进行依赖注入。

六、IOC容器初始化 —— BeanDefinition解析

七、依赖注入过程

通常,我们可以通过lazy-init属性控制Bean的实例化(依赖注入)时机。 当lazy-init=true时,依赖注入会发生在第一次向容器获取Bean时(getBean);当lazy-init=false时,会在容器初始化的过程中将所有的singleton bean提前进行实例化和依赖注入,因此singleton bean的依赖注入是容器初始化过程中的一部分,这也是我们常用的ApplicationContext的默认配置。

一、getBean触发依赖注入

  • getBean getBean方法定义在BeanFactory接口中,以DefaultListableBeanFactory为例,其基类AbstractBeanFactory中实现了getBean方法。
  • createBean 这个方法用来创建Bean实例,并进行一些处理。其一、创建Bean实例;其二、进行依赖注入。
  • createBeanInstance createBeanInstance通过适当的实例化策略来创建一个Bean实例,这里需要注意Spring5.0的新特性:通过设置Bean创建回调来覆盖工厂方法和构造函数。 在这个过程中,通过默认构造方法(无参构造)是基本的实例化策略,这个策略Spring的实现中提供了两种创建Bean的方式:其一,通过JVM反射创建Bean实例;其二,通过cglib动态代理创建Bean实例。
  • populateBean 这里是依赖注入的核心,在这里,首先由InstantiationAwareBeanPostProcessors进行依赖注入前的处理,判断是否对Bean的Property进行注入,接下来先处理autowire的注入,这里的autowire指的是在配置文件中通过autowire="byName"或者autowire="byType"等属性配置的bean,最后处理Property属性注入。

二、Bean的预实例化

当为Bean配置了lazy-init=false属性时,IOC容器会在初始化的时候对Bean进行预实例化,这时将会提前触发Bean的依赖注入过程,我们回到AbstractApplicationContext的refresh方法中,这里是IOC容器初始化的入口,在这个方法中我们可以看到调用了finishBeanFactoryInitialization方法,这个方法将会对非延迟加载的单例Bean进行预实例化。