对Spring IOC控制反转的详细理解

IOC是什么

    Spring的IOC意思为控制反转,它不是什么技术,而是一种设计思想。它是将你设计好的对象交给Spring容器来控制,而不是由我来管理对象,给它赋值等等。

问题一:谁控制谁?控制什么

    传统的面向对象思想对于构造对象最简单的方法无非就是在对象内部通过new对对象进行创建,是程序主动去创建依赖对象。
    但IOC不同,IOC是专门有一个容器来创建、初始化这些对象,这些对象被称为Bean。谁控制谁? 是IOC容器控制住了对象控制了什么? 控制了bean的生命周期。

问题二:为何是反转,哪方面反转了

    有反转就有正转,面向对象思想就是有我们在自己的对象中主动控制去直接获取依赖对象,这就是正转。而反转就是由Spring容器来创建及注入依赖对象。为何是反转? 因为有容器来自动的帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转。哪方面反转了? 依赖对象的获取被反转了。

DI依赖注入

    IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。在生产bean的过程中,需要解决bean之间的依赖问题,才引入了依赖注入(DI)这种技术。也就是说依赖注入是beanFactory生产bean时为了解决bean之间的依赖的一种技术而已。

对象如何生成(BeanFactory和ApplicationContext的区别)

    刚说的IOC就是由Spring来接手对象的创建、生命周期和对象间的关系。

    Spring的本质就是一个bean工厂或者说bean容器,它按照我们的需求创作出各种各样的bean。
    beanFactory会在bean的生命周期的各个阶段中对bean进行各种管理,并且spring将这些阶段通过各种接口暴露给我们,让我们可以对bean进行各种处理,我们只要让bean实现对应的接口,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。

BeanFactory和ApplicationContext

    在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义 了管理 bean 的最基本的方法。主要是面向spring框架本身,不支持AOP和web功能. 在获取bean时才会创建beanApplicationContext 继承BeanFactory接口,对功能进行扩展. 支持aop,web等插件,面向开发层面, 可以在框架启动时,就可以创建bean。如果说BeanFactory是心脏,那么ApplicationContext就是躯体。
在这里插入图片描述

Bean的生命周期

在这里插入图片描述

IOC控制了Bean的生命周期,就是Spring管理Bean的过程,

  1. 实例化,等同于new
  2. 属性赋值、注入
  3. 初始化,根据各种配置进行对象初始化。例如类具有事务管理功能,再次阶段生成代理对象。
    1. 若Bean实现了BeanNameAware接口,调用setBeanName(),将bean的id传给setBeanName
    2. 若Bean实现了BeanFactoryAware接口,调用setApplicationContext() 进行初始化
    3. 若Bean实现了ApplicationContextAware接口,调用setApplicationContext() 进行初始化
    4. 若Bean实现了BeanPostProcessor接口(AOP),调用postProcessBeforeInitialization() 进行初始化
    5. 若Bean实现了InitializingBean接口 或 bean使用<bean init-method="初始化方法">声明了初始化方法,调用afterPropertiesSet()进行初始化
    6. 若Bean实现了BeanPostProcessor接口(AOP),调用postProcessAfterInitialization() 进行初始化
  4. Bean的使用然后销毁阶段

在这里插入图片描述

Bean的线程安全

Spring中的Bean不是线程安全的

    线程安全问题,还需要从单例bean和原型bean说起
    线程安全问题是指在单咯bean的情况下,对象值创建了一个。如果拥有成员变量,它是共享的,所以线程不安全,可以使用ThreadLocal为每个线程申请一个变量副本,来解决线程安全问题。这种情况是单例Bean。在单例的设计模式中,对象只创建一次,多线程共享一个Bean对象,存在并发编程问题。而原型Bean是没有线程安全问题的,因为每个线程申请进来都会创建一个Bean对象,他们之间不存在成员变量共享问题。
在这里插入图片描述

Bean的循环依赖

什么是循环依赖?

    在JavaSE中,循环依赖是很正常的现象。比如A类的属性有B类的对象,B类的属性又有A类的对象。这就叫循环依赖。在使用的时候没有问题。
在这里插入图片描述
    但是在Spring中,对象的创建不是我们在操作,而是Spring容器,他会给对象注入值。对象的创建需要为其注入依赖对象的值才可以,A的创建需要注入B,但是B的创建有需要注入A,问题就来了,不解决的话会陷入死循环。归根结底 循坏依赖的本质问题就是Spring不允许为对象注入Null值

如何解决循环依赖?
在这里插入图片描述
三层缓存机制:

  1. 一级缓存 singletonObjects:保存实例化、属性注入、初始化完成的Bean
  2. 二级缓存 earlySingletonObjects:保存实例化完成的Bean(实例化完成,对象不为null,就可以注入,解决了循环依赖)
  3. 三级缓存 singletonFactories:保存Bean工厂,以便后期添加其他代理对象(如事务管理中代理对象的生成)

构造方法注入无法解决循环依赖问题
在构造方法中使用@Lazy标识依赖的属性参数,可以解决

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值