日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

字节跳动面试题:“请你描述下 Spring Bean 的生命周期?”

發(fā)布時間:2025/3/21 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字节跳动面试题:“请你描述下 Spring Bean 的生命周期?” 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 引言

“請你描述下 Spring Bean 的生命周期?”,這是面試官考察 Spring 的常用問題,可見是 Spring 中很重要的知識點(diǎn)。

我之前在準(zhǔn)備面試時,去網(wǎng)上搜過答案,大多以下圖給出的流程作為答案。

但是當(dāng)我第一次看到該圖時,就產(chǎn)生了很多困擾,“Aware,BeanPostProcessor......這些都是什么啊?而且這么多步驟,太多了,該怎么記啊?”。

其實要記憶該過程,還是需要我們先去理解,本文將從以下兩方面去幫助理解 Bean 的生命周期:

  • 生命周期的概要流程:對 Bean 的生命周期進(jìn)行概括,并且結(jié)合代碼來理解;
  • 擴(kuò)展點(diǎn)的作用:詳細(xì)介紹 Bean 生命周期中所涉及到的擴(kuò)展點(diǎn)的作用。
  • 2. 生命周期的概要流程

    Bean 的生命周期概括起來就是?4 個階段

  • 實例化(Instantiation)
  • 屬性賦值(Populate)
  • 初始化(Initialization)
  • 銷毀(Destruction)
  • 實例化:第 1 步,實例化一個 bean 對象;
  • 屬性賦值:第 2 步,為 bean 設(shè)置相關(guān)屬性和依賴;
  • 初始化:第 3~7 步,步驟較多,其中第 5、6 步為初始化操作,第 3、4 步為在初始化前執(zhí)行,第 7 步在初始化后執(zhí)行,該階段結(jié)束,才能被用戶使用;
  • 銷毀:第 8~10步,第8步不是真正意義上的銷毀(還沒使用呢),而是先在使用前注冊了銷毀的相關(guān)調(diào)用接口,為了后面第9、10步真正銷毀 bean 時再執(zhí)行相應(yīng)的方法。
  • 下面我們結(jié)合代碼來直觀的看下,在 doCreateBean() 方法中能看到依次執(zhí)行了這 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. 銷毀-注冊回調(diào)接口try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}return exposedObject; }

    由于初始化包含了第 3~7步,較復(fù)雜,所以我們進(jìn)到 initializeBean() 方法里具體看下其過程(注釋的序號對應(yīng)圖中序號):

    // AbstractAutowireCapableBeanFactory.java protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 3. 檢查 Aware 相關(guān)接口并設(shè)置相關(guān)依賴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. 若實現(xiàn) InitializingBean 接口,調(diào)用 afterPropertiesSet() 方法// 6. 若配置自定義的 init-method方法,則執(zhí)行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. 若實現(xiàn) DisposableBean 接口,則執(zhí)行 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 方法,則執(zhí)行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 的源碼我們可以直觀的看到其執(zhí)行過程,而我們記憶其過程便可以從這 4 個階段出發(fā),實例化、屬性賦值、初始化、銷毀。其中細(xì)節(jié)較多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。這些都是 Spring 提供的擴(kuò)展點(diǎn),其具體作用將在下一節(jié)講述。

    3. 擴(kuò)展點(diǎn)的作用

    3.1 Aware 接口

    若 Spring 檢測到 bean 實現(xiàn)了 Aware 接口,則會為其注入相應(yīng)的依賴。所以通過讓bean 實現(xiàn) Aware 接口,則能在 bean 中獲得相應(yīng)的 Spring 容器資源

    Spring 中提供的 Aware 接口有:

  • BeanNameAware:注入當(dāng)前 bean 對應(yīng) beanName;
  • BeanClassLoaderAware:注入加載當(dāng)前 bean 的 ClassLoader;
  • BeanFactoryAware:注入 當(dāng)前BeanFactory容器 的引用。
  • 其代碼實現(xiàn)如下:

    // 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 接口的注入實現(xiàn),是通過 BeanPostProcessor 的方式注入的,但其作用仍是注入依賴。

  • EnvironmentAware:注入 Enviroment,一般用于獲取配置屬性;
  • EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于參數(shù)解析;
  • ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。
  • 其代碼實現(xiàn)如下:

    // 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 **提供的強(qiáng)大擴(kuò)展點(diǎn),其可作用于容器中所有 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;}}

    常用場景有:

  • 對于標(biāo)記接口的實現(xiàn)類,進(jìn)行自定義處理。例如3.1節(jié)中所說的ApplicationContextAwareProcessor,為其注入相應(yīng)依賴;再舉個例子,自定義對實現(xiàn)解密接口的類,將對其屬性進(jìn)行解密處理;
  • 為當(dāng)前對象提供代理實現(xiàn)。例如 Spring AOP 功能,生成對象的代理類,然后返回。
  • // AbstractAutoProxyCreator.java public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());// 返回代理類return proxy;}return null; }

    3.3 InitializingBean 和 init-method

    InitializingBean 和 init-method 是 Spring 為?bean 初始化提供的擴(kuò)展點(diǎn)。

    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. 總結(jié)

    最后總結(jié)下如何記憶 Spring Bean 的生命周期:

    • 首先是實例化、屬性賦值、初始化、銷毀這 4 個大階段;
    • 再是初始化的具體操作,有 Aware 接口的依賴注入、BeanPostProcessor 在初始化前后的處理以及 InitializingBean 和 init-method 的初始化操作;
    • 銷毀的具體操作,有注冊相關(guān)銷毀回調(diào)接口,最后通過DisposableBean 和 destory-method 進(jìn)行銷毀。

    總結(jié)

    以上是生活随笔為你收集整理的字节跳动面试题:“请你描述下 Spring Bean 的生命周期?”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。