本文涉及点:
- 一 .spring Bean的作用域
- 二. Spring Bean的生命周期
一. spring Bean的作用域
- singleton: Spring的默认作用域,容器里拥有唯一的Bean实例
- prototype:针对每个getBean请求,容器都会创建一个Bean实例
____下面三个比较少用________________________________________________
- request:会为每个Http请求创建一个Bean实例
- session:会为每个session创建一个Bean实例
- globalSession:会为每个全局Http Session创建一个Bean实例,该作用域仅对Portlet有效
二. Spring Bean的生命周期
- 1、实例化一个Bean--也就是我们常说的new;
- 2、按照Spring上下文对实例化的Bean进行属性配置;
- 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
- 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的 setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
- 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
- 3、如果这个Bean关联了BeanPostProcessor(Spring后置处理器)接口,那么将会调用postProcess
Before
Initialization(Object obj, String s)方法做一些自定义的预处理, 它是在我们这个Bean 实例化、依赖注入后,初始化前调用,这点非常重要,Spring 的 AOP 就是利用它实现的。 - 4、如果Bean在Spring配置文件中配置了
init-method属性
会自动调用其配置的初始化方法。 - 5 、如果这个Bean关联了BeanPostProcessor(Spring后置处理器)接口,将会调用postProcess
After
Initialization(Object obj, String s)方法,它是在我们这个Bean 实例化、依赖注入、初始化都完成后调用。
注:以上工作完成以后就可以应用这个Bean了。 - 6 、当Bean不再需要时,会经过清理阶段,如果Bean实现了
DisposableBean
这个接口,会调用它实现的destroy()方法销毁;如果这个Bean的Spring配置中配置了destroy-method
属性,那么会调用其配置的销毁方法销毁bean。
关于上面系列的XXXAware,我的理解是Aware:意识到的,Aware本身是一个空接口,没有任何方法,我觉得他其实相当于一个标识,因为我们很多Bean可能不可避免的要用到spring的一些资源,但是不可能所有的bean都需要一样的信息,那么spring提供了xxx资源很多xxxAware,我们特定的bean需要啥xxx资源就实现这个aware,spring在设置这个bean的时候就把这个资源给设置进去了。
比如说:如果这个Bean已经实现了ApplicationContextAware接口,spring容器就会调用我们的bean的setApplicationContext(ApplicationContext)方法,传入Spring上下文,把spring容器给传递给这个bean。
关于Aware 详细可以看
如何追踪声明周期可以看
三. Spring 单例Bean是线程安全的吗?
3.1 Spring Bean是线程安全吗?
看情况吧,比如说,我们bean里面写了一些可变成员变量,然后可以进行修改和添加,那并发下肯定会有并发问题的呀;
3.2如何解决呢?
一般情况下,我们常用的 Controller
、Service
、Dao
这些 Bean 是无状态的。无状态的 Bean 不能保存数据,因此是线程安全的。
对于一定要有数据变更操作的,常见的有 2 种解决办法:
- 在类中定义一个
ThreadLocal
成员变量,将需要的可变成员变量保存在 ThreadLocal
中(推荐的一种方式)。 - 改变 Bean 的作用域为
prototype
:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。