专栏首页后台技术底层理解Spring IOC源码最全分析

Spring IOC源码最全分析

IOC 控制反转

1. Spring IOC 的原理?

spring ioc 即控制反转,就是将我们创建和管理对象交给了spring进行处理; 我们只需要通过配置文件描述对象, 容器加载配置文件描述,并将其转换为Bean Difinition , 然后通过BeanFactory 来生产对象,当然单利在创建一次后会缓存在bean容器中。

Spring IOC 主要实现依赖于 工厂模式 + 反射;

2. Spring IOC 容器有什么?

  1. BeanFactory
  2. ApplicationContext

BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。 ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。

3. Spring load 作为bean定义的过程?

定义bean可以通过xml <bean> 标签的形式进行配置;其次现在使用注解形式进行配置;

  1. 在 @Configuration 类文件中通过 @Bean进行配置
  2. 通过@ComponentScan 包,@server,@controller等进行配置
  3. 通过 @Import进行导入;
@Import // 导入一个普通类到spring容器,可以有几种方式:
  1. @import(value = {InstC.class})
  2. // 通过在注册器中,构造bean定义并通过import导入,spring整合mybatis @import(value = {ImportBeanDifinitionRegister.class})
  3. // 通过类的相对类名,包,可以导入批量,实现importSelector ,springboot 自动装配原理 @imoprt(value = {ImportSelector.class})

加载过程是:

  1. .class 的字节码文件,通过JVM 类加载器加载到内存,
  2. 通过@import,@componentScan,@Bean 等将其转换为Bean Definition,
  3. 将其存储在BeanDefinitionMap 中,key BeanName,value 就是对象;

4. Spring Bean definition 定义 ?

image.png

spring 将配置解析为bean定义:

class: 类路径名

scope: 单利,原型

autowaremode: 注入模型

lazyInit 是否是懒加载

默认注入模型是 0, 在使用的时候必须加@Autoware

可以在后置处理器修改注入模型,1,2 分别是byName, byType, 在类中必须写setXXX方法 它就会自动的注入进去;

懒加载,依赖,构造参数等记录;

5. BeanFactoryPostProcessor

spring 提供一个扩展机会再bean definition 还没进行实例化的时候,还可以对其进行扩展。 修改我们bean definition 的属性;

BeanFactoryPostProcessor 修改的是我们的bean定义,相当于修改的是类型,而不是具体的实例;

BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,在父类的基础上,增加了新的方法,允许我们获取到BeanDefinitionRegistry,从而编码动态修改BeanDefinition。例如往BeanDefinition中添加一个新的BeanDefinition。

BeanDefinitionRegistryPostProcessor,这也就是我们在@import中实现第二种方法的原理;

也就是在getBean 之前进行调用;

6. BeanPostProcessor

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法调用后被调用
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

BeanPostProcessor 是在我们bean进行初始化前后进行工作;

它是在getBean()后对bean进行初始化前后进行调用;

7. spring mvc 启动过程

  1. 创建一个servletContext 容器,将我们 Rootconfig保存到容器中;
  2. 创建一个contextLoaderListener, 注册到 servletContext中;
  3. 创建一个空的子容器,将webConfig,保存到中,setParent(servletContext),将servletContext作为父容器;
  4. 创建一个dispatcherServlet,并将其注册到子容器中
  5. contextLoaderListener,和 dispatcherServlet会进行刷新容器,将bean加载到我们容器中;

8. 容器刷新,创建Bean的过程

spring 容器启动流程:

  1. 刷新容器,标记容器启动
  2. 将配置信息解析,注册到BeanFactory
  3. 实例化BeanFactoryPostProcessor,调用beanFactoryPostProcessor修改bean definition
  4. 注册 beanpostprocessors
  5. 初始化当前的事件广播器
  6. 初始化所有非懒加载单例 singleton beans(lazy-init 的除外) 7.初始化容器的生命周期事件处理器,并发布容器的生命周期事件
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 刷新前准备工作
      prepareRefresh();

      // 调用子类refreshBeanFactory()方法,获取bean factory
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 创建bean Factory的通用设置
      prepareBeanFactory(beanFactory);

      try {
         // 子类特殊的bean factory设置
         postProcessBeanFactory(beanFactory);

         // 实例化beanFactoryPostProcessor
         // 调用beanFactoryPostProcessor修改bean definition
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册 bean pst processors
         registerBeanPostProcessors(beanFactory);

         // 初始化信息源,和国际化相关
         initMessageSource();

         // 初始化容器事件传播器
         initApplicationEventMulticaster();

         // 调用子类特殊的刷新逻辑
         onRefresh();

         // 为事件传播器注册事件监听器
         registerListeners();

         // 实例化所有非懒加载单例
         finishBeanFactoryInitialization(beanFactory);

         // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
         finishRefresh();
      }

      catch (BeansException ex) {
         // ...
      }
      finally {
         // ...
      }
   }
}

9. springBean 的生命周期

bean 的生命周期指的是getBean后的生命周期;

spring bean 容器的生命周期流程如下:

  1. Spring 容器根据配置中的 bean 定义中实例化 bean。 2. Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
  2. 如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。
  3. 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
  4. 如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
  5. 如果为 bean 指定了 init 方法(<bean> 的 init-method 属性),那么将调用它。
  6. 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。 8. bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
  7. 如果为 bean 指定了 destroy 方法(<bean> 的 destroy-method 属性),那么将调用它

DI大概是这样的,根据我们要获取的BeanName,去IOC容器中找到对应的class,然后实例化出一个代理类对象,然后给这个对象的属性赋值。

10. 展开具体DI依赖注入过程

  1. 获取bean 的name,如果是别名将其转换
  2. 从缓存中取得单利bean
  3. 缓存中没有单利bean,判断是否可以在当前BeanFactory中获取单利bean,否则委托当前容器的父容器去寻找,按名字和类型
  4. 没有的话,创建bean

3.1 判断是不是原型实例,如果是,则抛出创建失败异常,如果不是,下一步。

3.2 检查 BeanDefinition 是否在当前的容器中,如果不在那可能在父类容器中,所以委托父类容器查找,如果还没有,则再上一级容器...递归查找。

3.3 检查这个实例是否是为了类型检查而获取,而不是用来使用,如果是,标记这个bean已经被创建,如果不是,下一步。

3.4 根据 beanName获取 父类的BeanDefinition,并检查该对象类类型,比如不能是抽象类等。

3.5 根据 beanName获取所有该 bean依赖的 Bean集合,如果该集合有值,则遍历DI(递归调用 getBean())该 bean集合里的bean,并把bean注册给当前的bean(维护了一个 map来存放关系)。

3.6 如果3.4中获取的 BeanDefinition是单例,则根据该单例对象和 beanName和 args创建一个实例对象;否则,判断 BeanDefinition是否是原型,如果是则根据 beanName,该对象, args创建一个实例;否则拿到3.4获取的 BeanDefinition对象的生命周期 Scope,然后根据 scope来创建实例对象,参数 (beanName,bd,args)。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Bean的解析和加载详细解释

    Core Container 包含 Core,Beans,Context,Expression Language 模块 Core 和 Beans 提供 IOC...

    黑白格
  • spring-mybatis 整合分析

    我们知道只有将实体类或者抽象类注入到容器,接口是无法注入到容器中。spring-mybatis 是如何将接口注入到容器。

    黑白格
  • Spring装配Bean

    比如我在在类上添加注解@Component,这表明该类会作为组件类,并告知spring会为这个类创建Bean,但是组件扫描默认是不启动的,我们任然需要配值Spr...

    黑白格
  • Spring系列第12篇:lazy-init:bean延迟初始化

    在容器启动过程中被创建组装好的bean,称为实时初始化的bean,spring中默认定义的bean都是实时初始化的bean,这些bean默认都是单例的,在容器启...

    路人甲Java
  • 关于Spring面试题讲解2

    依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置...

    Java学习
  • 浅析spring——IOC 之 分析 bean 的生命周期

    在分析 Spring Bean 实例化过程中提到 Spring 并不是一启动容器就开启 bean 的实例化进程,只有当客户端通过显示或者隐式的方式调用 Bean...

    苏先生
  • 【死磕 Spring】----- IOC 之 分析 bean 的生命周期

    在分析 Spring Bean 实例化过程中提到 Spring 并不是一启动容器就开启 bean 的实例化进程,只有当客户端通过显示或者隐式的方式调用 Bean...

    用户1655470
  • day33_Spring学习回顾_01

    1、导入jar包:4 + 1 --> beans/core/context/expression + commons-logging

    黑泽君
  • spring中Bean的作用域

    在Spring中,那些组成你应用程序的主体(backbone)及由Spring IoC容器所管理的对象,被称之为bean。 简单地讲,bean就是由Spri...

    MickyInvQ
  • 快速学习-Spring(Bean的生命周期)

    cwl_java

扫码关注云+社区

领取腾讯云代金券