6. Spring Bean 的生命周期
Spring Bean 的生命周期可以分为四个大阶段:
- 实例化
- 属性赋值
- 初始化
- 销毁
具体步骤如下:
- 实例化 Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。
对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。 - 设置对象属性:实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。
- 处理 Aware 接口:Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:
①如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字; ②如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 ②如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。 ③如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文; - BeanPostProcessor 前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
- InitializingBean : 如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
- init-method :如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
- BeanPostProcessor 后置处理:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
- DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
- destroy-method:如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
7. Spring 中 bean 的作用域:
- singleton:默认作用域,单例,即每个容器中只会生成一个 bean 的实例;
- prototype:原型,为每一个bean 的请求都会创建一个新的实例;
- request:web 模式下的特性,为每一个 request 请求创建一个实例,在请求完成后 ,bean 会失效被GC回收;
- session:web模式下的特性,同一个 session 会话可以共享一个 bean 实例,不同的 session 会话使用不同的实例;
- global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。比如统计整个站点的在线人数等问题;
8. spring中的bean是线程安全的吗?
先说答案:Spring 不保证 bean 的线程安全, spring 的bean 线程安全取决于不同的条件。
spring 中的 bean 的默认作用域是 singleton,所以多个线程抢占同一个 bean 的使用权,肯定会出问题的;
把 spring 的 bean 作用域改为 prototype 后,就是单个线程操作一个 bean ,所以又不会出现线程安全问题;
但是有一些 bean 是无状态的,(不同的线程不会对这个bean 进行查询以外的操作,即不会存在说修改属性等)那么这个单例的 bean 就是线程安全的,比如 Conroller 类, Service 和 DAO;
那么如何解决有状态的 bean 的线程安全问题呢?
- 最浅显的解决办法就是将有状态的bean的作用域由
singleton
改为prototype
。 - 采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的副本变量。(关于 ThreadLocal 需要补课的小伙伴请自行补课,后期我也会出相关的知识点总结,一起学习,一起进步)。
9. Spring基于xml注入bean的几种方式:
- 构造注入(通过 index,通过类型)
- set 注入(需要显式定义 setter 方法)
- 静态工厂注入;
- 实例工厂;