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 对象并进行一系列的初始化工作。
- Spring Bean 元信息配置阶段,能够通过面向资源(XML 或 Properties)、面向注解、面向 API 进行配置
- Spring Bean 元信息解析阶段,对上一步的配置元信息进行解析,解析成 BeanDefinition 对象,该对象蕴含定义 Bean 的所有信息,用于实例化一个 Spring Bean
- Spring Bean 元信息注册阶段,将 BeanDefinition 配置元信息 保留至 BeanDefinitionRegistry 的 ConcurrentHashMap 汇合中
4-5 属于实例化阶段,想要生成一个 Java Bean 对象,那么必定须要依据 Bean 的元信息先实例化一个对象;
- Spring BeanDefinition 合并阶段,定义的 Bean 可能存在层次性关系,则须要将它们进行合并,存在雷同配置则笼罩父属性,最终生成一个 RootBeanDefinition 对象
- Spring Bean 的实例化阶段,首先的通过类加载器加载出一个 Class 对象,通过这个 Class 对象的结构器创立一个实例对象,结构器注入在此处会实现。在实例化阶段 Spring 提供了实例化前后两个扩大点。
接下来的 6
属于属性赋值阶段,实例化后的对象还是一个空对象,咱们须要依据 Bean 的元信息对该对象的所有属性进行赋值;
- Spring Bean 属性赋值阶段,在 Spring 实例化后,须要对其相干属性进行赋值,注入依赖的对象。首先获取该对象所有属性与属性值的映射,可能已定义,也可能须要注入,在这里都会进行赋值(反射机制)。提醒一下,依赖注入的实现通过 CommonAnnotationBeanPostProcessor(@Resource、@PostConstruct、@PreDestroy)和 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value)两个处理器实现的。
前面的 7
、8
、9
属于初始化阶段,在 Java Bean 对象生成后,可能须要对这个对象进行相干初始化工作才予以应用
- Aware 接口回调阶段,如果 Spring Bean 是 Spring 提供的 Aware 接口类型(例如 BeanNameAware、ApplicationContextAware),这里会进行接口的回调,注入相干对象(例如 beanName、ApplicationContext)
- Spring Bean 初始化阶段,这里会调用 Spring Bean 配置的初始化办法,执行程序:@PostConstruct 标注办法、实现 InitializingBean 接口的 afterPropertiesSet() 办法、自定义初始化办法。在初始化阶段 Spring 提供了初始化前后两个扩大点(BeanPostProcessor 的 postProcessBeforeInitialization、postProcessAfterInitialization 办法)
- Spring Bean 初始化实现阶段,在所有的 Bean(不是形象、单例模式、不是懒加载形式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象,如果是 SmartInitializingSingleton 类型则调用其 afterSingletonsInstantiated() 办法,这里也属于 Spring 提供的一个扩大点
最初面的 10
、11
属于销毁阶段,当 Spring 利用上下文敞开或者被动销毁某个 Bean 时,可能须要对这个对象进行相干销毁工作,最初期待 JVM 进行回收。
- Spring Bean 销毁阶段,当 Spring 利用上下文敞开或者你被动销毁某个 Bean 时则进入 Spring Bean 的销毁阶段,执行程序:@PreDestroy 注解的销毁动作、实现了 DisposableBean 接口的 Bean 的回调、destroy-method 自定义的销毁办法。这里也有一个销毁前阶段,也属于 Spring 提供的一个扩大点,@PreDestroy 就是基于这个实现的
- Spring 垃圾收集(GC)
下面