目录
BeanFactory 和 ApplicationContext
我们把由Spring创建的对象称为一个Bean , 关于Spring中 Bean存在很多的知识面, 例如生命周期, 循环依赖 , 接着我们来一一论述
BeanFactory 和 ApplicationContext
先来说BeanFactory , 顾名思义, 从名字上能看出, bean工厂, 是偏底层的一些东西
在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义了管理bean 的最基本的方法,例如获取实例、基本的判断等
这个接口中定义了一些基础的方法 , 例如 getBean()等, 当然作为底层接口, 也有很多子接口来进一步扩展bean的功能, 接着来看ApplicationContext
ApplicationContext也间接继承了BeanFactory,如果说BeanFactory是Sping的心脏,那么ApplicationContext 就是完整的身躯了。它们都可以当做 Spring的容器,Spring 容器是生成 Bean 实例的工厂,并管理容器中的 Bean。
接着来看两者的区别
首先BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,是 Spring 中比较原始的Factory,它不支持 AOP、Web 等 Spring 插件, 而 ApplicationContext 不仅包含了 BeanFactory 的所有功能,还支持 Spring的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承。
意思就是说BeanFactory比较底层, 没有许多额外的功能等, 而ApplicationContext则支持各种额外功能, 并且包含BeanFactory所有功能(因为它两是间接继承关系)
BeanFactory:需要等到获取某个 bean 的时候才会创建该 bean,即延迟初始化 ApplicationContext:在启动 Spring 容器时就会创建所有的 bean(Web 应用中推荐)
BeanFactory等到需要的时候才会创建, 而ApplicationContext在Spring容器启动时就会创建所有的bean
SpringBean的生命周期
宏观上讲 , bean生命周期有5个阶段
1. 实例化 Instantiation 2. 属性赋值 Populate 3. 初始化 Initialization 4. 将 bean 对象放入到容器中,使用 5. 销毁 Destruction
实例化
就是创建一个原始的对象, 通过反射机制实现
属性赋值
为所创建的对象中属性赋值
初始化
这里的初始化主要有两点 :
1. 如果类实现了某些接口并重写了接口中的某些方法 , 就去执行这些方法, 初始化我们的对象 , 对类进行了功能提升
2. 如果此类是一个被增强的类(AOP), 那么就是在此处为bean添加功能
使用
此时bean已被加入到spring容器中, 可以使用
销毁
如果 Bean 实现 DisposableBean 执行 destroy , 如果配置了自己的销毁方法<bean destroy-method="customerDestroy"> , 指定销毁方法 customerDestroy
以上就是bean生命周期的整个过程, 中间有很多过程都是初始化时是否执行某些方法, 如果没有实现这些接口, 那么这些过程也可以省略, 下图为上面过程的解释
Spring 中的 Bean 是线程安全的吗 ?
Spring 容器中的 Bean 是否线程安全,容器本身并没有提供 Bean 的线程安全策略,因此可以说Spring 容器中的 Bean 本身不具备线程安全的特性,但是具体还是要结合具体 scope(作用域) 的 Bean 情况。
要谈论线程安全问题的话 , 可以分为单例 bean和原型 bean来探讨
原型Bean : 每次都创建一个新对象 , 线程之间并不存在共享的bean , 自然不存在线程安全问题
单例Bean : 多个线程共享一个Bean , 是存在线程安全问题的
bean 又可以分为有状态和无状态
有状态就是bean中包含可以操作的变量数据等, 而无状态则不包含这些
如果单例bean 是一个无状态bean(没有向外界提供数据操作) , 毋庸置疑, 此时它就是线程安全的 , 但如果它是一个有状态的bean , 那么就存在线程安全问题 ,需要开发人员自己保证线程安全
Bean循环依赖
Bean的循环依赖问题就是 两个对象相互依赖, 导致两个对象都无法创建
试想我们不使用spring , 在javaSE中这种情况会出现吗 ? 答案当然是不会
因为在创建A 时, 发现有B ,会赋null ,B同理 , 所以这种情况只在spring中出现(spring是自动注入的)
spring中的bean和我们普通的对象不同 , 它需要经过一系列的生命周期, 所以如果出现循环依赖问题, 两者此时都无法创建, 那么如何来解决这一问题呢?
为解决此问题, spring提供了三级缓存
singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的 bean 实例 earlySingletonObjects 二级缓存,用于保存实例化完成的 bean 实例
singletonFactories 三级缓存,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。
那么这三个缓存是怎样来解决此问题的 , 接着我们来论述
假如现在有两个bean,A和B相互依赖 , 首先创建A , 先创建A的原始对象(实例化), 发现A中包含B, 此时这个半成品A会最终存入到二级缓存中, 接着去创建 B , 发现B 中包含A , 将二级缓存中的A取出注入到B中, 此时B被创建完成, 存入一级缓存中 , 这时回到创建A的过程, 将一级缓存中的B取出赋给A 中, 至此循环依赖问题解决
那么这时可能有人会说了, 不是有3级缓存吗? 那第三层缓存呢? 接着我们来说
其实在解决依赖之前, 第三级缓存就已经使用过了(感兴趣可以去看源码具体实现), 但它最主要的功能是解决功能增强问题(AOP) , 就是说我们发现A中B存在要增强的功能 , 那么此时二级缓存就无法顾及这么多了, 三级缓存做到了缓存工厂, 可以对bean进行加工 . 所以可以得出结论 : 二级缓存主要解决依赖问题, 三级缓存解决功能增强问题(AOP)