关于spring:深入了解Spring-IOC

37次阅读

共计 3386 个字符,预计需要花费 9 分钟才能阅读完成。

1. 你对 Spring IoC 的了解?

IOC 容器理论就是指的 spring 容器。从容器概念、管制反转、依赖注入三个方面答复这个问题:
1. 容器概念
实际上就是个 map(key,value),外面存的是各种对象(在 xml 里配置的 bean 节点、@repository、@service、@controller、@component),在我的项目启动的时候会读取配置文件外面的 bean 节点,依据全限定类名应用反射创建对象放到 map 里、扫描到上述注解的类,通过反射创建对象放到 map 里。

这个时候 map 里就有各种对象了,接下来咱们在代码里须要用到外面的对象时,再通过 DI(依赖)注入(autowired、resource 等注解,xml 里 bean 节点内的 ref 属性,我的项目启动的时候会读取 xml 节点 ref 属性依据 id 注入,也会扫描这些注解,依据类型或 id 注入;id 就是对象名)。

2. 管制反转
没有引入 IOC 容器之前,对象 A 依赖于对象 B,那么对象 A 在初始化或者运行到某一点的时候,本人必须被动去创建对象 B 或者应用曾经创立的对象 B。无论是创立还是应用对象 B,控制权都在本人手上。

引入 IOC 容器之后,对象 A 与对象 B 之间失去了间接分割,当对象 A 运行到须要对象 B 的时候,IOC 容器会被动创立一个对象 B 注入到对象 A 须要的中央。

通过前后的比照,不难看出来:对象 A 取得依赖对象 B 的过程, 由被动行为变为了被动行为,控制权颠倒过去了,这就是“管制反转”这个名称的由来。

全副对象的控制权全副上缴给“第三方”IOC 容器,所以,IOC 容器成了整个零碎的要害外围,它起到了一种相似“粘合剂”的作用,把零碎中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去分割,这就是有人把 IOC 容器比喻成“粘合剂”的由来。

3. 依赖注入
“取得依赖对象的过程被反转了”。管制被反转之后,取得依赖对象的过程由本身治理变为了由 IOC 容器被动注入。依赖注入是实现 IOC 的办法,就是由 IOC 容器在运行期间,动静地将某种依赖关系注入到对象之中。

2. IoC 和 DI 的区别?

DI 依赖注入不齐全等同于 IoC,Spring 框架是一个 IoC 容器的实现,DI 依赖注入是它的实现的一个形式或策略,IOC 提供依赖查找和依赖注入两种依赖解决,治理着 Bean 的生命周期。

依赖查找 依赖注入 都是 IoC 的实现策略。依赖查找 就是在应用程序外面被动调用 IoC 容器提供的接口去获取对应的 Bean 对象,而 依赖注入 是在 IoC 容器启动或者初始化的时候,通过结构器、字段、setter 办法或者接口等形式注入依赖。依赖查找 相比于 依赖注入 对于开发者而言更加繁琐,具备肯定的代码入侵性,须要借助 IoC 容器提供的接口,所以咱们总是强调后者。依赖注入在 IoC 容器中的实现也是调用相干的接口(autowired、resource 等获取 Bean 对象,只不过这些工作都是在 IoC 容器启动时由容器帮忙实现了,在应用程序中咱们通常很少被动去调用接口获取 Bean 对象。

3.DI 依赖注入的形式区别(结构器注入和 Setter 注入)

结构器注入:通过结构器的参数注入相干依赖对象

Setter 注入:通过 Setter 办法注入依赖对象,也能够了解为字段注入

对于两种注入形式的认识:

  • 结构器注入能够防止一些难堪的问题,比如说状态不确定性地被批改,在初始化该对象时才会注入依赖对象,肯定水平上保障了 Bean 初始化后就是不变的对象,这样对于咱们的程序和维护性都会带来更多的便当;
  • 结构器注入不容许呈现循环依赖,因为它要求被注入的对象都是成熟态,保障可能实例化,而 Setter 注入或字段注入没有这样的要求;
  • 结构器注入能够保障依赖的对象可能有序的被注入,而 Setter 注入或字段注入底层是通过反射机制进行注入,无奈齐全保障注入的程序;
  • 如果结构器注入呈现比拟多的依赖导致代码不够优雅,咱们应该思考本身代码的设计是否存在问题,是否须要重构代码构造。

Spring Bean 的生命周期?
生命周期:

1- 3 属于 BeanDefinition 配置元信息阶段,BeanDefinition 是 Spring Bean 的“前身”,其外部蕴含了初始化一个 Bean 的所有元信息,在 Spring 初始化一个 Bean 的过程中须要依据该对象生成一个 Bean 对象并进行一系列的初始化工作。

  1. Spring Bean 元信息配置阶段,能够通过面向资源(XML 或 Properties)、面向注解、面向 API 进行配置
  2. Spring Bean 元信息解析阶段,对上一步的配置元信息进行解析,解析成 BeanDefinition 对象,该对象蕴含定义 Bean 的所有信息,用于实例化一个 Spring Bean
  3. Spring Bean 元信息注册阶段,将 BeanDefinition 配置元信息 保留至 BeanDefinitionRegistry 的 ConcurrentHashMap 汇合中

4-5 属于实例化阶段,想要生成一个 Java Bean 对象,那么必定须要依据 Bean 的元信息先实例化一个对象;

  1. Spring BeanDefinition 合并阶段,定义的 Bean 可能存在层次性关系,则须要将它们进行合并,存在雷同配置则笼罩父属性,最终生成一个 RootBeanDefinition 对象
  2. Spring Bean 的实例化阶段,首先的通过类加载器加载出一个 Class 对象,通过这个 Class 对象的结构器创立一个实例对象,结构器注入在此处会实现。在实例化阶段 Spring 提供了实例化前后两个扩大点。

接下来的 6 属于属性赋值阶段,实例化后的对象还是一个空对象,咱们须要依据 Bean 的元信息对该对象的所有属性进行赋值;

  1. Spring Bean 属性赋值阶段,在 Spring 实例化后,须要对其相干属性进行赋值,注入依赖的对象。首先获取该对象所有属性与属性值的映射,可能已定义,也可能须要注入,在这里都会进行赋值(反射机制)。提醒一下,依赖注入的实现通过 CommonAnnotationBeanPostProcessor(@Resource、@PostConstruct、@PreDestroy)和 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value)两个处理器实现的。

前面的 789 属于初始化阶段,在 Java Bean 对象生成后,可能须要对这个对象进行相干初始化工作才予以应用

  1. Aware 接口回调阶段,如果 Spring Bean 是 Spring 提供的 Aware 接口类型(例如 BeanNameAware、ApplicationContextAware),这里会进行接口的回调,注入相干对象(例如 beanName、ApplicationContext)
  2. Spring Bean 初始化阶段,这里会调用 Spring Bean 配置的初始化办法,执行程序:@PostConstruct 标注办法、实现 InitializingBean 接口的 afterPropertiesSet() 办法、自定义初始化办法。在初始化阶段 Spring 提供了初始化前后两个扩大点(BeanPostProcessor 的 postProcessBeforeInitialization、postProcessAfterInitialization 办法)
  3. Spring Bean 初始化实现阶段,在所有的 Bean(不是形象、单例模式、不是懒加载形式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象,如果是 SmartInitializingSingleton 类型则调用其 afterSingletonsInstantiated() 办法,这里也属于 Spring 提供的一个扩大点

最初面的 1011 属于销毁阶段,当 Spring 利用上下文敞开或者被动销毁某个 Bean 时,可能须要对这个对象进行相干销毁工作,最初期待 JVM 进行回收。

  1. Spring Bean 销毁阶段,当 Spring 利用上下文敞开或者你被动销毁某个 Bean 时则进入 Spring Bean 的销毁阶段,执行程序:@PreDestroy 注解的销毁动作、实现了 DisposableBean 接口的 Bean 的回调、destroy-method 自定义的销毁办法。这里也有一个销毁前阶段,也属于 Spring 提供的一个扩大点,@PreDestroy 就是基于这个实现的
  2. Spring 垃圾收集(GC)

下面

正文完
 0