JavaBean的生命周期
一:基本概念
bean 就是由IOC 容器初始化、装配及管理的对象。
Spring中的bean默认都是单例的,那么单例Bean在多线程程序下如何保证线程安全呢?
Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于 JVM,每个 JVM 内只有一个实例。所以非分布式服务情况下,单例Bean可以保证线程安全。
二:Bean的作用范围
创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的“配方”。把bean定义看成一个配方很有意义,它与class很类似,只根据一张“处方”就可以创建多个实例。不仅可以控制注入到对象中的各种依赖和配置值,还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域,而不必在Java Class级定义作用域。
Spring Framework支持五种作用域,分别阐述如下表。
我眼中的Bean其实就是一个机器模板,根据一张模板,可以生产出不同的类型机器。
五种作用域中,request、session 和 global session 三种作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于 web 的 Spring ApplicationContext 环境。
详细描述如下:
- singleton——唯一 bean 实例
当一个 bean 的作用域为 singleton,那么Spring IoC容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回bean的同一实例。 singleton 是单例类型(对应于单例模式),就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,但我们可以指定Bean节点的 lazy-init=”true” 来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。 每次获取到的对象都是同一个对象。注意,singleton 作用域是Spring中的缺省作用域。要在XML中将 bean 定义成 singleton ,可以这样配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
也可以通过 @Scope 注解(它可以显示指定bean的作用范围。)的方式
@Service
@Scope("singleton")
public class ServiceImpl{
}
- prototype——每次请求都会创建一个新的 bean 实例
当一个bean的作用域为 prototype,表示一个 bean 定义对应多个对象实例。 prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法**)时都会创建一个新的 bean 实例。prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。 在 XML 中将 bean 定义成 prototype ,可以这样配置:
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
通过 @Scope 注解的方式实现就不做演示了。
注意事项:
作用域为 prototype 的 bean ,其destroy方法并没有被调用。如果 bean 的 scope 设为prototype时,当容器关闭时,destroy 方法不会被调用。对于 prototype 作用域的 bean,有一点非常重要,那就是 Spring不能对一个 prototype bean 的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。 不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用)。
谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java new操作的替代者,任何迟于该时间点的生命周期事宜都得交由客户端来处理。
Spring 容器可以管理 singleton 作用域下 bean 的生命周期,在此作用域下,Spring 能够精确地知道bean何时被创建,何时初始化完成,以及何时被销毁。而对于 prototype 作用域的bean,Spring只负责创建,当容器创建了 bean 的实例后,bean 的实例就交给了客户端的代码管理,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的bean的生命周期。
- request——每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效
request只适用于Web程序,每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,当请求结束后,该对象的生命周期即告结束。 在 XML 中将 bean 定义成 request ,可以这样配置:
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
- session——每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效
session只适用于Web程序,session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效.与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的 HTTP session 中根据 userPreferences 创建的实例,将不会看到这些特定于某个 HTTP session 的状态变化。当HTTP session最终被废弃的时候,在该HTTP session作用域内的bean也会被废弃掉。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
- globalSession
global session 作用域类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portle t所共享。在global session 作用域中定义的 bean 被限定于全局portlet Session的生命周期范围内。
<bean id="user" class="com.foo.Preferences "scope="globalSession"/>
三:bean的生命周期
引用:https://zhuanlan.zhihu.com/p/108198655
Bean 的生命周期概括起来就是 4 个阶段
- 实例化(Instantiation)
- 属性赋值(Populate)
- 初始化(Initialization)
- 销毁(Destruction)
实例化过程:
BeanWrapper调用createBeanInstance方法。
属性赋值:
bean 设置相关属性和依赖
初始化:
(主要了解Bean在实例)
Aware接口:
- Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。
BeanFactory 类型的容器
- BeanNameAware:注入当前 bean 对应 beanName;
- BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader(类加载器);
- BeanFactoryAware:注入 当前BeanFactory容器 的引用。
ApplicationContext 类型的容器
- EnvironmentAware:注入 Enviroment,一般用于获取配置属性;
- EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于参数解析;
- ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。
BeanPostProcessor后置处理器
public interface BeanPostProcessor {
// 初始化前置处理
default Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
return bean;
}
// 初始化后置处理
default Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
return bean;
}
}
InitializingBean 和 init-method 是 Spring 为 bean 初始化提供的扩展点。(可以扩展初始化逻辑)
DisposableBean 和 destory-method是 Spring 为 bean 销毁提供的扩展点。
bean生命周期详细过程如下:(结合学习)
- ResouceLoader加载配置信息
- 解析配置信息,生成一个一个的BeanDefintion
- BeanDefintion由BeanDefintionRegistry管理起来
- BeanFactoryPostProcessor对配置信息进行加工(也就是处理配置的信息,一般通过PropertyPlaceholderConfigurer来实现)
- 实例化Bean
- 如果该Bean配置/实现了InstantiationAwareBean,则调用对应的方法
- 使用BeanWarpper来完成对象之间的属性配置(依赖)
- 如果该Bean配置/实现了Aware接口,则调用对应的方法
- 如果该Bean配置了BeanPostProcessor的before方法,则调用
- 如果该Bean配置了init-method或者实现InstantiationBean,则调用对应的方法
- 如果该Bean配置了BeanPostProcessor的after方法,则调用
- 将对象放入到HashMap中
- 最后如果配置了destroy或者DisposableBean的方法,则执行销毁操作
总结:
首先是实例化、属性赋值、初始化、销毁这 4 个大阶段
再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;(或**@PostConstruct注解**)
销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。(@PreDestory注解也可实现)