Spring IOC原理

概述

  • IOC 的作用:解耦、单例缓存、Bean生命周期管理、父子容器
  • IOC 工作要经历2个过程:启动预加载BeanDefination、实例化对象且缓存单例,传统BeanFactory的实现类是懒加载(loadClass时再实例化bean),而web容器实现是预加载(启动和实例化一起进行)。但是BeanDefination都是预加载的。

IOC的作用

  1. 解耦:
  • 实现了类与类依赖关系的解耦,大家都注册在IOC容器当中,并不直接强耦合。有多种注入类的方式:xml配置、@Component 注解、@import、@Configuration等等
  • 实现了类的依赖关系和代码的解耦:把类的依赖关系,可以不通过修改代码,而是通过修改 xml然后容器来实现,这给非开发人员带来了很多便利
  1. 单例缓存:基于容器注册,就可以灵活缓存,避免内存空间的浪费,提升创建bean的速度。如果通过new的方式,就无法做到。
  2. 预处理:对Bean生成进行干预(init、构造函数、属性赋值、对象销毁)等过程进行干预
  3. 父子容器:MVC的实现就是很好的例子,既有一定的隔离性,又可以复用父容器的类

IOC容器启动和创建Bean逻辑

image

总体逻辑:IOC容器启动时,把所有配置过的Bean都全部各自生成一个BeanDefinition,并存储到BeanDefinitionRegistry的beanDefinitionMap中;用户在通过BeanFactory接口的实现类去getBean的时候,会从beanDefinitionMap中获取到这个bean的BeanDefinition,然后通过反射生成一个Bean,默认单例的话,还会把这个实例化的bean存储在singletonObjects中,下次再getBean的时候就直接从singletonObjects中返回

  1. 在IOC容器启动的时候,去扫描指定的application.xml,从而获取到需要注册的Bean的信息,不管你后期会不会用到这个Bean,所有扫到的Bean都会各自封装成一个BeanDefinition
  2. 因为Spring默认是懒加载,只有程序getBean的时候才会真正的实例化这个Bean,而实例化Bean的时候需要知道这个Bean的BeanDefinition(因为BeanDefinition里面有这个Bean的所有相关信息),所以需要BeanDefinitionRegistry这个BeanDefinition的管理器,来判断这个Bean是否已经注册生成了BeanDefinition,否则只有遍历所有创建过的BeanDefinition,才能知道你要get的这个Bean是否已经生成BeanDefinition
  3. BeanDefinitionRegistry接口主要负责管理所有注册过的BeanDefinition,比如增删改查功能,他的实现类需要2个工具成员变量:beanDefinitionMap、singletonObjects(都是ConcurrentHashMap结构)
  4. beanDefinitionMap负责缓存所有注册过的BeanDefinition;singletonObjects为单例类的缓存器,每个通过BeanDefinitionRegistry创建出来的bean,都缓存在singletonObjects里面,除非是多例
  5. 而BeanFactory接口是面向用户的,实际上他只是一个触发器,用户调用getBean方法,会先去beanDefinitionMap查找这个Bean是否已经生成了BeanDefinition,没有就报错,有就根据BeanDefinition来反射创建一个Bean,因为默认是单例的,创建完之后就缓存在singletonObjects里面

Spring getBean流程的细节

  1. 缓存查询:查询singletonObjects中是否有缓存
  2. 实例化DependsOn的类:查询类A是否是dependsOn的类,有的话,需要先实例化dependsOn的类
  3. 创建一个空的实体类:读取BeanDefinition信息,获取空的构造函数,通过反射创建一个所有filed为null的实体类(这样在堆中就有一个引用了)然后把这个Bean保存到singletonFactories中(以参数的形式 把bean存到factory里面)
  4. 然后遍历该类A的依赖属性,一一赋值,如果属性值依赖的是某一个具体的类B的时候,就必须先实例化B类
  5. 最后把创建好的Bean缓存在singletonObjects中,再返回给调用者

Spring 生命周期管理

  1. 实例化Bean执行顺序:调用构造函数、属性值的set方法、init方法(如果配置了的话)、destory方法
  2. 类通过实现特定的接口,来实现在某个过程中进行干预
  3. Spring 也支持配置容器级别的 干预类,注入到IOC当中后,所有的类在创建过程中,都会收到干预

普通Java Bean的生命周期

比如main方法里面,new User()这个操作,就会从class文件里面加载一个User对象到JVM里。

JavaBean的生命周期:类加载、连接、验证、准备、初始化

  • 其中包括类静态成员变量的初始化为默认值
  • 静态成员变量设置为设置值或者静态代码块的执行
  • 调用构造函数

另外Java 加载Bean的触发条件:

  1. new的方式直接创建
  2. 当前类的静态属性或者静态方法被调用
  3. 该类作为父类被加载等等

你可能感兴趣的:(Spring IOC原理)