一、簡介
首先,為什么要學習 Spring 中 Bean 的生命周期呢?
雖然不了解 Bean 的生命周期,并不影響日常工作中的開發(fā)。但是如果我們了解了 Bean 的生命周期,可以幫助我們更好地掌握 Spring 框架,并且能夠讓我們更好地去理解 Spring 容器是如何管理和創(chuàng)建 Bean 示例的。如果以后遇到 Bean 的相關問題(比如 Spring 的循環(huán)依賴問題),就可以方便我們去調試和解決這些問題。同時也讓我們可以編寫出更健壯、靈活、易維護的應用程序。所以說,理解 Bean 的生命周期對掌握 Spring 框架來說是至關重要的。
這里我們主要分兩部分去說明:
- 先從整體上去介紹 Bean 創(chuàng)建的整個流程 -> Bean的流程;
- 然后再用代碼的方式去驗證流程 -> 代碼驗證。
二、Bean的流程
1.BeanDefinition
BeanDefinition
:Bean 的定義信息。Spring 容器在進行實例化時,會將 xml 配置中 <bean>
的信息(注解也是如此)封裝成一個 BeanDefinition 對象,Spring 根據(jù) BeanDefinition 來創(chuàng)建 Bean 對象,里面有很多用來描述 Bean 的屬性。
有了 BeanDefinition 之后,再去創(chuàng)建 Bean 對象的時候,就可以通過反射
去創(chuàng)建。
<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl" lazy-init="true"/>
<bean id="userService" class="com.demo.service.UserServiceImpl" scope="singleton">
<property name="userDao" ref="userDao"></property>
</bean>

-
beanClassName
:bean 的類名。 -
initMethodName
:初始化方法名稱。 -
propertyValues
:bean 的屬性值。 -
scope
:作用域。 -
lazyInit
:延遲初始化。
以上這些屬性都被封裝到 BeanDefinition 中備用。那具體什么時候用呢?這就是下面要說的 Bean 的生命周期。
2.Bean 的生命周期
目前我們已經有了 BeanDefinition 這個對象了,那第一步就是要去創(chuàng)建對象。
-
第1步,調用 Bean 的構造函數(shù)。 來去實例化當前 Bean 的對象。
-
第2步,依賴注入。 像是一些
@Autowired
或者@Value
標明的屬性,這些都是在依賴注入中完成。 -
第3步,Aware接口。 比較常見的有三個,它們都是以 Aware 結尾的接口,如果 Bean 實現(xiàn)了這些接口,就要重寫里面的方法:
BeanNameAware
:在初始化過程中可以獲取到 Bean 的名稱。BeanFactoryAware
:在初始化過程中可以獲取到 Bean 工廠。ApplicationContextAware
:在初始化過程中可以獲取到應用上下文。以上這些內容都是為了方便對 Bean 進行擴展。
-
第4步,BeanPostProcessor#before。 BeanPostProcessor 是 Bean 的后置處理器,用來增強 Bean 的功能的,在初始化方法調用之前(before)進行回調。這個 BeanPostProcessor 后置處理器在 Bean 的生命中其中占有非常重要的作用,需要重點記憶。
-
第5步,調用初始化方法。 里面有兩部分:
InitializingBean
:這是一個接口類,如果當前 Bean 實現(xiàn)了這個接口的話,就要重寫里面的方法,這一步就是來執(zhí)行重寫之后的方法。自定義init方法
:比如在 Bean 中的某一個方法使用了注解@PostConstruct
,這里就會去執(zhí)行標明了注解的方法。其實自定義init方法也是從 BeanDefinition 中讀取到的信息。 -
第6步,BeanPostProcessor#after。 還是在 Bean 的后置處理器中執(zhí)行,但是是在初始化方法之后(after)執(zhí)行。在 Spring 中對 Bean 進行增強的話,都是用到這個初始化方法之后執(zhí)行的后置處理器。其實在 Spring 內部就使用到了很多的后置處理器,比較典型的就是:當一個類被曾倩了,使用到了
AOP
,那這個類通常都是使用后置處理器(BeanPostProcessor#after)來增強的。我們知道 AOP 的底層使用的是動態(tài)代理,有兩種:JDK動態(tài)代理
、CGLIB動態(tài)代理
。到這一步之后,基本上這個對象就創(chuàng)建完成了,現(xiàn)在就可以從 Spring 容器中去獲取和使用這個 Bean 對象了。
注意: 從
依賴注入
開始到BeanPostProcessor#after
完成之后,都是針對當前的 Bean 進行初始化賦值,當然也做了一些增強。這里需要注意,Spring 中 Bean 的創(chuàng)建是一步一步完成的,也就是說 Bean 的創(chuàng)建和初始化賦值是分開的。調用構造函數(shù)就是創(chuàng)建 Bean 對象,但是這里創(chuàng)建好后是一個空對象,里面沒有值,下面就是初始化賦值的過程。 -
第6步,銷毀Bean。 當 Spring 容器關閉之后,這個 Bean 對象就要執(zhí)行銷毀的操作了。比較典型的是,如果在某個方法上使用了
@PreDestroy
這個注解,那這個方法就是一個銷毀的方法,Spring 容器關閉的時候就會執(zhí)行這個銷毀的方法。
以上就是 Bean 的生命周期,里面的步驟還是挺多的。為了方便加深印象,我們可以用代碼的方式去驗證一下。
三、代碼驗證
1.User 實體類
User.java
繼承了 BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
、InitializingBean
接口。
package com.demo.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
public User() {
System.out.println("User類的構造方法被調用了...");
}
/**
* 姓名
*/
private String name;
@Value("張三")
public void setName(String name) {
System.out.println("setName方法被調用了...");
this.name = name;
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware接口的setBeanName方法被調用了,bean的名字是:" + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware接口的setBeanFactory方法被調用了...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware接口的setApplicationContext方法被調用了...");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean接口的afterPropertiesSet方法被調用了...");
}
@PreDestroy
public void destroy() {
System.out.println("PreDestroy注解的destroy方法被調用了...");
}
}
2.MyBeanPostProcessor 后置處理器
MyBeanPostProcessor.java
定義了 #before
和 #after
方法的增強實現(xiàn)。
package com.demo.lifecycle;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("BeanPostProcessor接口的postProcessBeforeInitialization方法被調用了 -> user對象初始化方法前開始增強....");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (Objects.equals(beanName, "user")) {
System.out.println("BeanPostProcessor接口的postProcessAfterInitialization方法被調用了 -> user對象初始化方法后開始增強....");
// cglib代理對象
/*Enhancer enhancer = new Enhancer();
// 設置需要增強的類
enhancer.setSuperclass(bean.getClass());
// 執(zhí)行回調方法,增強方法
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// 執(zhí)行目標方法
return method.invoke(bean, objects);
}
});
// 創(chuàng)建代理對象
return enhancer.create();*/
}
return bean;
}
}
3.SpringConfig 掃描包配置
SpringConfig.java
配置了掃描包位置,只掃描 User 實體類和 MyBeanPostProcessor 后置處理器。
package com.demo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.demo.lifecycle")
public class SpringConfig {
}
4.UserTest 測試類
UserTest.java
main 方法執(zhí)行,使用 SpringConfig
配置創(chuàng)建上下文,并從容器中獲取 user
的 Bean 對象。
package com.demo.test;
import com.demo.config.SpringConfig;
import com.demo.lifecycle.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class UserTest {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = ctx.getBean(User.class);
System.out.println(user);
}
}
5.測試結果
由于我使用的是 SpringBoot 項目進行的測試,會多打印一些日志,其中不帶時間前綴的是我們手動 println
的日志。
Connected to the target VM, address: '127.0.0.1:61642', transport: 'socket'
20:03:56.949 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@9660f4e
20:03:56.985 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
20:03:57.100 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\IdeaProjects\SpringBootExamples\springboot-demo\target\classes\com\demo\lifecycle\MyBeanPostProcessor.class]
20:03:57.105 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\IdeaProjects\SpringBootExamples\springboot-demo\target\classes\com\demo\lifecycle\User.class]
20:03:57.266 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
20:03:57.270 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
20:03:57.272 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
20:03:57.275 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
20:03:57.281 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanPostProcessor'
20:03:57.304 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfig'
BeanPostProcessor接口的postProcessBeforeInitialization方法被調用了 -> user對象初始化方法前開始增強....
20:03:57.305 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
User類的構造方法被調用了...
setName方法被調用了...
BeanNameAware接口的setBeanName方法被調用了,bean的名字是:user
BeanFactoryAware接口的setBeanFactory方法被調用了...
ApplicationContextAware接口的setApplicationContext方法被調用了...
BeanPostProcessor接口的postProcessBeforeInitialization方法被調用了 -> user對象初始化方法前開始增強....
InitializingBean接口的afterPropertiesSet方法被調用了...
BeanPostProcessor接口的postProcessAfterInitialization方法被調用了 -> user對象初始化方法后開始增強....
User類的構造方法被調用了...
com.demo.lifecycle.User@2235eaab
Disconnected from the target VM, address: '127.0.0.1:61642', transport: 'socket'
Process finished with exit code 0
可以看到日志是按照我們梳理的 Bean 的生命周期順序打印的,驗證完畢。
6.模擬AOP增強
MyBeanPostProcessor.java
的 postProcessAfterInitialization()
方法中注釋了 AOP 底層 CGLIB 動態(tài)代理的演示代碼的,可以在 UserTest
的 main
方法中獲取到 user
的 Bean 對象后,將鼠標放到 user 上看下,打開和關閉 CGLIB 代理的注釋生成的 user Bean 會不同:
關閉 CGLIB 代理:
打開 CGLIB 代理:
三、總結
問: Spring 中 Bean 的生命周期是什么樣的?
答:
① 通過 BeanDefinition 獲取 Bean 的定義信息;
② 調用構造函數(shù)實例化 Bean;
③ Bean 的依賴注入;
④ 處理 Aware 接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware);
⑤ Bean 的后置處理器 BeanPostProcessor-前置;
⑥ 初始化方法(InitializingBean、init-method);
⑦ Bean 的后置處理器 BeanPostProcessor-后置;
⑧ 銷毀 Bean。
整理完畢,完結撒花~ ??
參考地址:文章來源:http://www.zghlxwxcb.cn/news/detail-630032.html
1.框架篇-05-Spring-bean的生命周期,https://www.bilibili.com/video/BV1yT411H7YK/?p=39&spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=cf16f2e5f7c4612add10f9f9268a2c8a文章來源地址http://www.zghlxwxcb.cn/news/detail-630032.html
到了這里,關于Spring(11) Bean的生命周期的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!