Spring中bean的初始化和銷(xiāo)毀幾種實(shí)現(xiàn)方式詳解
Bean的生命周期 : 創(chuàng)建bean對(duì)象 – 屬性賦值 – 初始化方法調(diào)用前的操作 – 初始化方法 – 初始化方法調(diào)用后的操作 – …-- 銷(xiāo)毀前操作 – 銷(xiāo)毀方法的調(diào)用。
【1】init-method和destroy-method
自定義初始化方法和銷(xiāo)毀方法兩種方式:xml配置和注解。
① xml配置
<bean id="person" class="com.core.Person" scope="singleton" init-method="init" destroy-method="cleanUp" autowire="byName" lazy-init="true" > </bean>
② 注解配置
@Scope("singleton")
@Lazy
@Bean(name="person",initMethod="init",destroyMethod="cleanUp",
autowire=Autowire.BY_NAME)
public Person person01(){
return new Person("lisi", 20);
}
單實(shí)例bean在容器創(chuàng)建完成前會(huì)進(jìn)行創(chuàng)建并初始化,在容器銷(xiāo)毀的時(shí)候進(jìn)行銷(xiāo)毀。多實(shí)例bean(scope=prototype)在第一次獲取該bean實(shí)例時(shí)才會(huì)創(chuàng)建并初始化,且容器不負(fù)責(zé)該bean的銷(xiāo)毀。
【2】InitializingBean 和DisposableBean
InitializingBean 接口:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在BeanFactory設(shè)置完bean屬性后執(zhí)行
需要被bean實(shí)現(xiàn)的接口,一旦bean的屬性被BeanFactory設(shè)置后需要做出反應(yīng): 如,執(zhí)行自定義初始化,或者僅僅是檢查是否設(shè)置了所有強(qiáng)制屬性。
實(shí)現(xiàn)InitializingBean 的可替代方式為給bean指定一個(gè)自定義的init-method,例如在一個(gè)xml bean 定義中。
在bean的屬性設(shè)置之后進(jìn)行操作,不返回任何值但是允許拋出異常。
DisposableBean接口:
public interface DisposableBean {
void destroy() throws Exception;
}
被bean實(shí)現(xiàn)的接口,在銷(xiāo)毀時(shí)釋放資源,在Bean銷(xiāo)毀的時(shí)候調(diào)用該方法。
如果銷(xiāo)毀一個(gè)緩存的單例,一個(gè)BeanFactory 可能會(huì)調(diào)用這個(gè)銷(xiāo)毀方法。
在容器關(guān)閉時(shí),應(yīng)用上下文會(huì)銷(xiāo)毀所有的單例bean。
一種替代實(shí)現(xiàn)DisposableBean 接口的方案為指定一個(gè)自定義的destroy-method方法,例如在一個(gè)xml bean定義中。
自定義bean實(shí)現(xiàn)上述兩個(gè)接口
@Component
public class Cat implements InitializingBean,DisposableBean {
public Cat(){
System.out.println("cat constructor...");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat...afterPropertiesSet...");
}
}
測(cè)試結(jié)果
cat constructor...
cat...afterPropertiesSet...
容器創(chuàng)建完成...
四月 08, 2018 6:35:46 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext
doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347:
startup date [Sun Apr 08 18:35:46 CST 2018]; root of context hierarchy
cat...destroy...
【3】@PostConstruct和@PreDestroy
使用JSR250規(guī)范定義的兩個(gè)注解:
@PostConstruct: PostConstruct注解作用在方法上,在依賴(lài)注入完成后進(jìn)行一些初始化操作。這個(gè)方法在類(lèi)被放入service之前被調(diào)用,所有支持依賴(lài)項(xiàng)注入的類(lèi)都必須支持此注解。
@PreDestroy:在容器銷(xiāo)毀bean之前通知我們進(jìn)行清理工作
自定義類(lèi)使用上述兩個(gè)注解
@Component
public class Dog implements ApplicationContextAware {
//@Autowired
private ApplicationContext applicationContext;
public Dog(){
System.out.println("dog constructor...");
}
//對(duì)象創(chuàng)建并賦值之后調(diào)用
@PostConstruct
public void init(){
System.out.println("Dog....@PostConstruct...");
}
//容器移除對(duì)象之前
@PreDestroy
public void detory(){
System.out.println("Dog....@PreDestroy...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
}
測(cè)試結(jié)果如下
dog constructor...
Dog....@PostConstruct...
容器創(chuàng)建完成...
四月 08, 2018 6:42:11 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext
doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347:
startup date [Sun Apr 08 18:42:10 CST 2018]; root of context hierarchy
Dog....@PreDestroy...
【4】BeanPostProcessor-Bean后置處理器
① 什么是bean后置處理器
在bean初始化前后進(jìn)行一些處理工作
- postProcessBeforeInitialization:在初始化之前工作
- postProcessAfterInitialization:在初始化之后工作
其接口源碼如下:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
自定義MyBeanPostProcessor實(shí)現(xiàn)該接口:
/**
* 后置處理器:初始化前后進(jìn)行處理工作
* 將后置處理器加入到容器中
* @author lfy
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanPostProcessor.postProcessBeforeInitialization..."+beanName+"=>"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanPostProcessor.postProcessAfterInitialization..."+beanName+"=>"+bean);
return bean;
}
}
② BeanPostProcessor原理
AbstractAutowireCapableBeanFactory中關(guān)于bean和BeanPostProcessor執(zhí)行次序由上到下
//給bean進(jìn)行屬性賦值
populateBean(beanName, mbd, instanceWrapper);
//然后調(diào)用initializeBean方法
Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)
{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
//執(zhí)行自定義初始化
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
AbstractAutowireCapableBeanFactory.initializeBean源碼如下:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//調(diào)用意識(shí)/通知方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//調(diào)用bean后置處理器的前置方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//調(diào)用初始化方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// //調(diào)用bean后置處理器的后置方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
AbstractAutowireCapableBeanFactory.invokeInitMethods方法源碼如下:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
//調(diào)用InitializingBean.afterPropertiesSet
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
//調(diào)用自定義初始化方法
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
【5】Spring底層使用BeanPostProcessor
Spring框架底層存在大量BeanPostProcessor,如下圖:

示例一 :BeanValidationPostProcessor是處理bean校驗(yàn)
其Javadoc如下:
/**
* Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations
* in Spring-managed beans, throwing an initialization exception in case of
* constraint violations right before calling the bean's init method (if any).
*
* @author Juergen Hoeller
* @since 3.0
*/
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {
private Validator validator;
private boolean afterInitialization = false;
//...
}
示例二:ApplicationContextAwareProcessor幫助獲取容器上下文
其Javadoc如下:
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
* implementation that passes the ApplicationContext to beans that
* implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware},
* {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware},
* {@link MessageSourceAware} and/or {@link ApplicationContextAware} interfaces.
*
* <p>Implemented interfaces are satisfied in order of their mention above.
*
* <p>Application contexts will automatically register this with their
* underlying bean factory. Applications do not use this directly.
*
* @author Juergen Hoeller
* @author Costin Leau
* @author Chris Beams
* @since 10.10.2003
* @see org.springframework.context.EnvironmentAware
* @see org.springframework.context.EmbeddedValueResolverAware
* @see org.springframework.context.ResourceLoaderAware
* @see org.springframework.context.ApplicationEventPublisherAware
* @see org.springframework.context.MessageSourceAware
* @see org.springframework.context.ApplicationContextAware
* @see org.springframework.context.support.AbstractApplicationContext#refresh()
*/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
//...
}
如【3】中的dog類(lèi)為例,其debug示意圖如下:

【6】初始化和銷(xiāo)毀方式測(cè)試
① 如果一個(gè)bean 綜合應(yīng)用下面六種種方式,執(zhí)行順序會(huì)怎樣呢
Bean類(lèi)如下:
public class Person implements InitializingBean,DisposableBean {
private String name;
private Integer age=1;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("Person(String name, Integer age) constructor"+this);
}
public Person() {
super();
System.out.println("Person() constructor"+age);
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// 自定義init方法
public void init(){
System.out.println("-----Person.init()-----"+this);
}
// 自定義銷(xiāo)毀方法
public void cleanUp(){
System.out.println("-----Person.cleanUp()-----"+this);
}
// InitializingBean的實(shí)現(xiàn)方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-----InitializingBean.afterPropertiesSet()-----"+this);
}
//DisposableBean 的實(shí)現(xiàn)方法
@Override
public void destroy() throws Exception {
System.out.println("-----DisposableBean.destroy()-----"+this);
}
//對(duì)象創(chuàng)建并賦值之后調(diào)用
@PostConstruct
public void init2(){
System.out.println("-----@PostConstruct-----"+this);
}
//容器移除對(duì)象之前
@PreDestroy
public void destory2(){
System.out.println("-----@PreDestroy-----"+this);
}
}
配置類(lèi)如下:
public class Person implements InitializingBean,DisposableBean {
private String name;
private Integer age=1;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("Person(String name, Integer age) constructor"+this);
}
public Person() {
super();
System.out.println("Person() constructor"+age);
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// 自定義init方法
public void init(){
System.out.println("-----Person.init()-----"+this);
}
// 自定義銷(xiāo)毀方法
public void cleanUp(){
System.out.println("-----Person.cleanUp()-----"+this);
}
// InitializingBean的實(shí)現(xiàn)方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-----InitializingBean.afterPropertiesSet()-----"+this);
}
//DisposableBean 的實(shí)現(xiàn)方法
@Override
public void destroy() throws Exception {
System.out.println("-----DisposableBean.destroy()-----"+this);
}
//對(duì)象創(chuàng)建并賦值之后調(diào)用
@PostConstruct
public void init2(){
System.out.println("-----@PostConstruct-----"+this);
}
//容器移除對(duì)象之前
@PreDestroy
public void destory2(){
System.out.println("-----@PreDestroy-----"+this);
}
}
測(cè)試結(jié)果如下:
// 創(chuàng)建并初始化
Person(String name, Integer age) constructorPerson{name='lisi', age=20}
-----@PostConstruct-----Person{name='lisi', age=20}
-----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20}
-----Person.init()-----Person{name='lisi', age=20}
//容器將要銷(xiāo)毀
-----@PreDestroy-----Person{name='lisi', age=20}
-----DisposableBean.destroy()-----Person{name='lisi', age=20}
-----Person.cleanUp()-----Person{name='lisi', age=20}
即,最先使用bean的構(gòu)造器為bean屬性賦值,接著JSR250規(guī)范定義的兩個(gè)注解,其次是InitializingBean和DisposableBean接口,最后才是我們自定義的初始化方法和銷(xiāo)毀方法。注意,這里還沒(méi)有引入BeanPostProcessor。
② 在①的基礎(chǔ)上添加BeanPostProcessor
實(shí)例化bean并進(jìn)行初始化
//調(diào)用構(gòu)造方法
Person(String name, Integer age) constructorPerson{name='lisi', age=20}
//bean初始化前
BeanPostProcessor.postProcessBeforeInitialization...person=>Person{name='lisi', age=20}
//初始化操作
-----@PostConstruct-----Person{name='lisi', age=20}
-----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20}
-----Person.init()-----Person{name='lisi', age=20}
//bean初始化后操作
BeanPostProcessor.postProcessAfterInitialization...person=>Person{name='lisi', age=20}
過(guò)程如下:類(lèi)構(gòu)造函數(shù)-->BeanPostProcessor-->@PostConstruct-->InitializingBean-->init()-->BeanPostProcessor
銷(xiāo)毀bean
-----@PreDestroy-----Person{name='lisi', age=20}
-----DisposableBean.destroy()-----Person{name='lisi', age=20}
-----Person.cleanUp()-----Person{name='lisi', age=20}
完整圖示如下(同顏色的說(shuō)明相對(duì)應(yīng)):

在調(diào)用bean的構(gòu)造函數(shù)時(shí)會(huì)根據(jù)入?yún)閎ean屬性賦值,如果入?yún)榭談t會(huì)給bean屬性賦予默認(rèn)值,引用類(lèi)型為null,基本類(lèi)型比如int為0。
【7】 @Autowired注解的值何時(shí)放入?
如下所示,redisTemplate這個(gè)依賴(lài)何時(shí)被容器注入到RedisController中?

通過(guò)上面分析可知,依賴(lài)注入是在@PostConstruct注解的方法調(diào)用前被完成的(在populateBean()方法中被注入):

那么具體什么時(shí)候哪個(gè)類(lèi)完成的 @Autowired注解注入依賴(lài)呢?
在類(lèi)被實(shí)例化后由BeanPostProcessor完成的,哪個(gè)BeanPostProcessor?
具體是由AutowiredAnnotationBeanPostProcessor 完成的:

到此這篇關(guān)于Spring中bean的初始化和銷(xiāo)毀幾種實(shí)現(xiàn)方式詳解的文章就介紹到這了,更多相關(guān)Spring中bean初始化和銷(xiāo)毀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中BigDecimal序列化科學(xué)計(jì)數(shù)法前端展示問(wèn)題踩坑實(shí)戰(zhàn)
BigDecimal是處理高精度的浮點(diǎn)數(shù)運(yùn)算的常用的一個(gè)類(lèi)當(dāng)需要將BigDecimal中保存的浮點(diǎn)數(shù)值打印出來(lái),這篇文章主要給大家介紹了關(guān)于Java中BigDecimal序列化科學(xué)計(jì)數(shù)法前端展示問(wèn)題踩坑的相關(guān)資料,需要的朋友可以參考下2024-04-04
@insert mybatis踩坑記錄,實(shí)體接收前端傳遞的參數(shù)
這篇文章主要介紹了@insert mybatis踩坑記錄,實(shí)體接收前端傳遞的參數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Spring Boot應(yīng)用啟動(dòng)時(shí)自動(dòng)執(zhí)行代碼的五種方式(常見(jiàn)方法)
Spring Boot為開(kāi)發(fā)者提供了多種方式在應(yīng)用啟動(dòng)時(shí)執(zhí)行自定義代碼,這些方式包括注解、接口實(shí)現(xiàn)和事件監(jiān)聽(tīng)器,本文我們將探討一些常見(jiàn)的方法,以及如何利用它們?cè)趹?yīng)用啟動(dòng)時(shí)執(zhí)行初始化邏輯,感興趣的朋友一起看看吧2024-04-04
解決springboot中配置過(guò)濾器以及可能出現(xiàn)的問(wèn)題
這篇文章主要介紹了解決springboot中配置過(guò)濾器以及可能出現(xiàn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
解析Java編程中設(shè)計(jì)模式的開(kāi)閉原則的運(yùn)用
這篇文章主要介紹了解析Java編程中設(shè)計(jì)模式的開(kāi)閉原則的運(yùn)用,開(kāi)閉原則多應(yīng)用于Java程序的擴(kuò)展開(kāi)發(fā)方面,需要的朋友可以參考下2016-02-02
java中的JsonSerializer用法,前后端單位轉(zhuǎn)換必備
這篇文章主要介紹了java中的JsonSerializer用法,前后端單位轉(zhuǎn)換必備!具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
datatables 帶查詢(xún)條件java服務(wù)端分頁(yè)處理實(shí)例
本篇文章主要介紹了datatables 帶查詢(xún)條件java服務(wù)端分頁(yè)處理實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

