一、IoC

IoC的职责主要有两个: 业务对象的构建管理 和 业务对象间的依赖绑定

1. IoC容器的设计

image.png

2. BeanFacoty容器

BeanFactory是基础类型IoC容器,提供完整的IoC服务支持,默认采用延迟初始化策略(lazy-load),只有当客户端访问时,才对该对象进行初始化以及依赖注入操作。2.1 拥有BeanFactory容器的好处

2.1 拥有BeanFactory的好处

系统业务对象需要自己去”拉”(Pull)所依赖的业务对象,有了BeanFactory容器之后,需要依赖什么让BeanFacotry为我们推过来(Push)就行了

2.2 BeanFactory的对象注册与依赖绑定方式

image.png
BeanFactory接口之定义如何访问容器内管理的bean,各个BeanFactory的具体实现类负责具体Bean的注册和管理工作.
BeanDefinitionRegistry 接口定义了抽象Bean的注册逻辑
DefaultListableBeanFactory 具体实现了BeanFactory、BeanDefinitionRegistry接口。

2.2.1 直接编码方式

2.2.2 外部配置文件方式

根据不同的外部配置文件格式,给出相应的BeanDefinitionReader实现类,由BeanDefinitionReader的相应实现类负责将相应的配置文件内容读取并映射到BeanDefinition,然后将映射后的BeanDefinition注册到一个BeanDefinitionRegistry,之后,BeanDefinitionRegistry完成Bean的注册和加载。
Properties文件格式
PropertiesBeanDefinitionReader
XML文件格式
XmlBeanDefinitionReader

2.2.3 注解方式

Scan相关 //todo

3. BeanFacotry - XML

xml文件就像是产品设计图,将Bean的定义和依赖按照规则描述清楚。
Spring提供了5种自动绑定模式,即 no、byName、byType、constructor和autodetect。

3.1 Bean的scope

  • singleton 单例,生命周期与ioc相同
  • prototype 多例,容器在接到该类型对象的请求的时候,会每次都重新生成一个新的对象实例请求方,此时该对象的生命周期就“自生自灭”了,容器就不再管理了。

    以下三个scope只适用于Web应用程序,通常与XmlWebApplicationContext共同使用

  • request : 每个http请求会创建一个全新的RequestProcessor对象共当前请求使用,当请求结束后,该对象实例的生命周期结束。request可以看做prototype的一种特例

  • session : 最普遍应用于存储用户的登录信息。 与request相比,除了拥有session scope的bean的实例具有比request scope的bean可能更长的存活时间,其他方面无差别
  • global session : 只有应用基于portlet的Web应用程序中才有意义,在基于servlet的Web应用中使用了这个类型的scope,容器会将其作为普通的session类型的scope
  • 自定义scope : 比如aop scope 涉及AOP的相关知识

    3.2 工厂方法与FactoryBean

    BeanFactory: 负责生产和管理Bean的一个工厂接口,提供一个Spring Ioc容器规范,
    FactoryBean: 一种Bean创建的一种方式,对Bean的一种扩展。对于复杂的Bean对象初始化创建使用其可封装对象的创建细节。
    注: 当某些对象的实例化过程过于反锁,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这个实例化过程的时候,或者,某些第三方库不能直接注册到Spring容器的时候,可以实现FactoryBean接口,给出自己的对象实例化逻辑代码。当然可以不适用FactorBean,而像通常那也实现自定义的工厂方法类也是可以的。不过,Factory是Spring官方提供的工具。
    FactoryBean类型的bean定义,通过正常的id引用,容器返回的是FactoryBean所“生产”的对象类型,而非FactoryBean实现本身,可以通过在bean定义的id之前加前缀&来达到目的。 ```java //FactoryBean的实现 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:application-ioc.xml”); Object nextDayDate = context.getBean(“nextDayDate”); Assert.isInstanceOf(DateTime.class,nextDayDate);

//获取factoryBean本身,在bean定义的id之前加前缀& 达到目的 Object factoryBean = context.getBean(“&nextDayDate”); Assert.isInstanceOf(FactoryBean.class,factoryBean); Assert.isInstanceOf(NextDayDateFactoryBean.class,factoryBean); ```

3.3 方法注入(Method Injection)以及方法替换(Method Replacement)

4. 容器启动和Bean的实例化

4.1 容器启动阶段

步骤: 加载配置 > 分析配置信息 > 装备到BeanDefinition > 注册到BeanDefinitionRegistry > 其他后处理
其他后处理(插手容器的启动):
Spring 提供了BeanFactoryPostProcessor的容器扩展机制。该机制允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改,比如修改bean定义的某些属性,为bean定义增加其他信息等。
我们可以自定义实现 BeanFactoryPostProcessor接口,因为一个容器可能有多个BeanFactoryPostProcessor,我们可以使用org.springframework.core.Ordered接口实现顺序执行。
Spring提供的几个例子

  • 通配符的替换 (org.springfarmework.beans.factory.config.PropertyPlaceholderConfigurer)

PropertyPlaceholderConfigurer允许我们在XML配置文件中使用占位符(PlaceHolder,如数据库的配置:${jdbc.username}),并将这些占位符所代表的资源单独配置到简单的properties文件中加载。
BeanFactory在第一阶段加载完成所有配置信息时,BeanFactory中保存的对象的属性信息还只是以占位符的形式存在,如${jdbc.url},PropertyPlaceholderConfigurer会使用properties配置文件中的信息来替换相应的BeanDefinition中占位符所标识的属性值。
PropertyPlaceholderConfigurer不仅会从其配置的properties中加载配置项,同时还会检测Java的Systm类中的Propeties,可以通过setSystemPropertiesMode()或者setSystemPropertiesModeName()来控制是否加载或者覆盖System相应Properties。PropertyPlaceholderConfigurer提供三种模式: SYSTEMPROPERTIES_MODE_NEVER(默认,即在properties中找不到时,则在System的Properties中找)、_SYSTEM_PROPERTIES_MODE_FALLBACK、SYSTEM_PROPERTIES_MODE_OVERRIDE。
//todo 需要理解使用注解,Spring怎么默认替换通配符的

  • 覆盖替换属性值(org.springfarmework.beans.factory.config.PropertyOverrideConfigurer)

使用properties定义的value值替换原来XML配置中的默认值,当有多个PropertyOverrideConfigurer对同一个bean定义的同一个property值进行处理时,最后一个将会生效。

  • 补助容器中默认的 PropertyEditor (org.springfarmework.beans.factory.config.CustomerEditorConfigurer)

与前两个不同,CustomerEditorConfigurer只是辅助性的将后期会用到的信息注册到容器,对BeanDefinition没有做任何变动。

  1. 概括: 该阶段主要是准备工作,侧重于对象管理信息的收集,当然一些验证性,辅助性的工作也可以在这个阶段完成。

4.2 Bean实例化阶段

步骤: 实例化对象 > 装配依赖 > 生命周期回调 > 对象其他处理 > 注册回调接口
概括: 容器会首先检查所请求的对象之前是否已经初始化。如果没有,根据注册的BeanDefination所提供的信息实例化被请求对象,并为其注入依赖。 如果改对象实现了某些回调接口,也会根据回调接口的要求来状态配。 当改独享装配完毕之后,容器会立即将其返回请求方使用。
image.png

1. Bean的实例化与BeanWrapper

采用策略模式决定采用何种方式初始化bean实例,通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类(默认情况下,容器内部采用CGLIB)。

2. 各色的Aware接口

3. BeanPostProcessor

  • Spring提供的BeanProcessor
  • 自定义BeanPostProcessor

    4. InitializingBean 和 init-method

5. DisposableBean 与 destroy-method

5. ApplicationContext

ApplicationContext是在BeanFactory基础构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,还提供了其他高级特性,比如时间发布、国际化信息支持等。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。

5.1. 统一资源加载策略

5.1.1 Spring中的Resource

5.1.2 ResourceLoader

5.2. 国际化信息支持

5.3. 容器内部事件发布

Spring的ApplicationContext容器内的事件发布机制,主要用于单一容器内的简单消息通知和处理,并不适合分布式、多进程、多肉那过期之间的事件通知。

5.4. 多配置模块加载的简化

6. 注解方式的实现

6.1 注解版的自动绑定(@Autowired)

@Autowired是按照类型匹配进行依赖注入的
@Qualifier是byName自动绑定的注解版
@Resource 遵循的是byName自动绑定的注解版

参考

  1. 《Spring揭秘》
  2. 博客
  3. 博客2
  4. 实例化流程图
  5. 源码拆分详解