javascript
字节跳动面试题:“请你描述下 Spring Bean 的生命周期?”
1. 引言
“請你描述下 Spring Bean 的生命周期?”,這是面試官考察 Spring 的常用問題,可見是 Spring 中很重要的知識點。
我之前在準備面試時,去網上搜過答案,大多以下圖給出的流程作為答案。
但是當我第一次看到該圖時,就產生了很多困擾,“Aware,BeanPostProcessor......這些都是什么啊?而且這么多步驟,太多了,該怎么記啊?”。
其實要記憶該過程,還是需要我們先去理解,本文將從以下兩方面去幫助理解 Bean 的生命周期:
2. 生命周期的概要流程
Bean 的生命周期概括起來就是?4 個階段:
下面我們結合代碼來直觀的看下,在 doCreateBean() 方法中能看到依次執行了這 4 個階段:
// AbstractAutowireCapableBeanFactory.java protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// 1. 實例化BeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}Object exposedObject = bean;try {// 2. 屬性賦值populateBean(beanName, mbd, instanceWrapper);// 3. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}// 4. 銷毀-注冊回調接口try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}return exposedObject; }由于初始化包含了第 3~7步,較復雜,所以我們進到 initializeBean() 方法里具體看下其過程(注釋的序號對應圖中序號):
// AbstractAutowireCapableBeanFactory.java protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 3. 檢查 Aware 相關接口并設置相關依賴if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}// 4. BeanPostProcessor 前置處理Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}// 5. 若實現 InitializingBean 接口,調用 afterPropertiesSet() 方法// 6. 若配置自定義的 init-method方法,則執行try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}// 7. BeanPostProceesor 后置處理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean; }在 invokInitMethods() 方法中會檢查 InitializingBean 接口和 init-method 方法,銷毀的過程也與其類似:
// DisposableBeanAdapter.java public void destroy() {// 9. 若實現 DisposableBean 接口,則執行 destory()方法if (this.invokeDisposableBean) {try {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((DisposableBean) this.bean).destroy();return null;}, this.acc);}else {((DisposableBean) this.bean).destroy();}}}// 10. 若配置自定義的 detory-method 方法,則執行if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);if (methodToInvoke != null) {invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));}}從 Spring 的源碼我們可以直觀的看到其執行過程,而我們記憶其過程便可以從這 4 個階段出發,實例化、屬性賦值、初始化、銷毀。其中細節較多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。這些都是 Spring 提供的擴展點,其具體作用將在下一節講述。
3. 擴展點的作用
3.1 Aware 接口
若 Spring 檢測到 bean 實現了 Aware 接口,則會為其注入相應的依賴。所以通過讓bean 實現 Aware 接口,則能在 bean 中獲得相應的 Spring 容器資源。
Spring 中提供的 Aware 接口有:
其代碼實現如下:
// AbstractAutowireCapableBeanFactory.java private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}} }以上是針對 BeanFactory 類型的容器,而對于 ApplicationContext 類型的容器,也提供了 Aware 接口,只不過這些 Aware 接口的注入實現,是通過 BeanPostProcessor 的方式注入的,但其作用仍是注入依賴。
其代碼實現如下:
// ApplicationContextAwareProcessor.java private void invokeAwareInterfaces(Object bean) {if (bean instanceof EnvironmentAware) {((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware)bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);}}3.2 BeanPostProcessor
BeanPostProcessor 是 Spring 為**修改 bean **提供的強大擴展點,其可作用于容器中所有 bean,其定義如下:
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;}}常用場景有:
3.3 InitializingBean 和 init-method
InitializingBean 和 init-method 是 Spring 為?bean 初始化提供的擴展點。
InitializingBean接口 的定義如下:
public interface InitializingBean {void afterPropertiesSet() throws Exception; }在 afterPropertiesSet() 方法寫初始化邏輯。
指定 init-method 方法,指定初始化方法:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="demo" class="com.chaycao.Demo" init-method="init()"/></beans>DisposableBean 和 destory-method 與上述類似,就不描述了。
4. 總結
最后總結下如何記憶 Spring Bean 的生命周期:
- 首先是實例化、屬性賦值、初始化、銷毀這 4 個大階段;
- 再是初始化的具體操作,有 Aware 接口的依賴注入、BeanPostProcessor 在初始化前后的處理以及 InitializingBean 和 init-method 的初始化操作;
- 銷毀的具體操作,有注冊相關銷毀回調接口,最后通過DisposableBean 和 destory-method 進行銷毀。
總結
以上是生活随笔為你收集整理的字节跳动面试题:“请你描述下 Spring Bean 的生命周期?”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis事务不具有回滚机制,那么它是如
- 下一篇: Linux中查看日志文件的正确姿势,求你