關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序
@PostConstruct、init-method、afterPropertiesSet() 執(zhí)行順序
想要知道 @PostConstruct、init-method、afterPropertiesSet() 的執(zhí)行順序,只要搞明白它們各自在什么時(shí)候被誰(shuí)調(diào)用就行了。
程序版本:Spring Boot 2.3.5.RELEASE
準(zhǔn)備好要驗(yàn)證的材料:
public class Foo implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet()"); } @PostConstruct public void init() { System.out.println("@PostConstruct"); } private void initMethod() { System.out.println("initMethod()"); } }
@Configuration public class FooConfiguration { @Bean(initMethod = "initMethod") public Foo foo() { return new Foo(); } }
執(zhí)行啟動(dòng)類(lèi),可以看到在控制臺(tái)中輸出:
@PostConstruct
afterPropertiesSet()
initMethod()
說(shuō)明執(zhí)行順序是:@PostConstruct、afterPropertiesSet()、init-method
接下來(lái)將跟著源碼來(lái)了解為什么是這個(gè)順序。
@PostConstruct 標(biāo)注的方法在何時(shí)被誰(shuí)調(diào)用
首先,在 init() 中打個(gè)斷點(diǎn),然后以 debug 的方式啟動(dòng)項(xiàng)目,得到下面的調(diào)用棧:
init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) doCreateBean:594, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) createBean:516, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) lambda$doGetBean$0:324, AbstractBeanFactory (org.springframework.beans.factory.support) getObject:-1, 2103763750 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$169) getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support) doGetBean:322, AbstractBeanFactory (org.springframework.beans.factory.support) getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support) preInstantiateSingletons:897, DefaultListableBeanFactory (org.springframework.beans.factory.support) finishBeanFactoryInitialization:879, AbstractApplicationContext (org.springframework.context.support) refresh:551, AbstractApplicationContext (org.springframework.context.support) refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context) refresh:758, SpringApplication (org.springframework.boot) refresh:750, SpringApplication (org.springframework.boot) refreshContext:405, SpringApplication (org.springframework.boot) run:315, SpringApplication (org.springframework.boot) run:1237, SpringApplication (org.springframework.boot) run:1226, SpringApplication (org.springframework.boot) main:14, InitApplication (com.xurk.init)
從上往下看,跳過(guò)使用 sun.reflect 的方法,進(jìn)入到第6行。
public void invoke(Object target) throws Throwable { ReflectionUtils.makeAccessible(this.method); this.method.invoke(target, (Object[]) null); }
很明顯,這里是在通過(guò)反射調(diào)用某個(gè)對(duì)象的一個(gè)方法,并且這個(gè)“某個(gè)對(duì)象”就是我們定義的 Foo的實(shí)例對(duì)象了。
那么這里的 method 又是在什么時(shí)候進(jìn)行賦值的呢?
invoke(...) 全路徑是:
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invoke
并且 LifecycleElement 有且只有一個(gè)顯示聲明并且?guī)?shù)的構(gòu)造器,這個(gè)要傳入構(gòu)造器的參數(shù)正是 invoke(...) 使用的那個(gè) Method 對(duì)象。
接下來(lái)就是查一下,是誰(shuí)在 new LifecycleElement 。
于是定位到:
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) { if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) { return this.emptyLifecycleMetadata; } List<LifecycleElement> initMethods = new ArrayList<>(); List<LifecycleElement> destroyMethods = new ArrayList<>(); Class<?> targetClass = clazz; do { final List<LifecycleElement> currInitMethods = new ArrayList<>(); final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method -> { if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) { logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); } } if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { currDestroyMethods.add(new LifecycleElement(method)); if (logger.isTraceEnabled()) { logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); } } }); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); }
第15-26行是在通過(guò)反射判斷方法上是否存在某個(gè)注解,如果是的話(huà)就加到一個(gè)集合中,在最后用于構(gòu)建 LifecycleMetadata 實(shí)例。
在這里因?yàn)槲覀円檎业氖潜毁x值的內(nèi)容,所以在使用IDE進(jìn)行查找時(shí)只要關(guān)注 write 相關(guān)的內(nèi)容就行了。
到這里,已經(jīng)知道了是在 CommonAnnotationBeanPostProcessor 的構(gòu)造器中進(jìn)行 set 的,也就是當(dāng)創(chuàng)建 CommonAnnotationBeanPostProcessor 實(shí)例的時(shí)候就會(huì)進(jìn)行賦值,并且 CommonAnnotationBeanPostProcessor 是 InitDestroyAnnotationBeanPostProcessor 的子類(lèi)。
并且,CommonAnnotationBeanPostProcessor 構(gòu)造器中調(diào)用的 setInitAnnotationType 其實(shí)是它父類(lèi)的方法,實(shí)際是對(duì) InitDestroyAnnotationBeanPostProcessor 的實(shí)例的 initAnnotationType 字段進(jìn)行賦值。
到這里已經(jīng)可以明確 buildLifecycleMetadata(...) 中判斷的正是 @PostConstruct。
再回到buildLifecycleMetadata(...) ,查看其使用的 doWithLocalMethods(...) 的實(shí)現(xiàn)。
public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) { Method[] methods = getDeclaredMethods(clazz, false); for (Method method : methods) { try { mc.doWith(method); } catch (IllegalAccessException ex) { throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex); } } }
很簡(jiǎn)單,通過(guò)反射獲得類(lèi)的所有方法,然后調(diào)用一個(gè)函數(shù)接口的方法,這個(gè)函數(shù)接口的實(shí)現(xiàn)就是判斷方法是不是被 @PostConstruct 標(biāo)注,如果被標(biāo)注的話(huà)放到一個(gè)名字叫 currInitMethods 的集合中。
看到這里或許你已經(jīng)意識(shí)到了, @PostConstruct 可以標(biāo)注多個(gè)方法,并且因?yàn)榉瓷浍@取方法時(shí)是根據(jù)聲明順序的、 currInitMethods 是 ArrayList,兩者之間的順序是一樣的。
好了,被 @PostConstruct 標(biāo)注的方法已經(jīng)找到放到集合中了,將被用來(lái)構(gòu)建 LifecycleMetadata 實(shí)例了。
buildLifecycleMetadata(...) 方法返回一個(gè) LifecycleMetadata 實(shí)例,這個(gè)返回值中包含傳入Class實(shí)例中得到的所有被 @PostConstruct 標(biāo)注的 Method 實(shí)例,接下來(lái)要看看是誰(shuí)在調(diào)用 buildLifecycleMetadata(...) 方法,看看它是怎么用的?
追溯到 findLifecycleMetadata(...) 而 findLifecycleMetadata(...) 又有好幾處被調(diào)用。
查看最早得到的方法調(diào)用棧,查到postProcessBeforeInitializatio(...) ,它又是再被誰(shuí)調(diào)用?
init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
跟著方法調(diào)用棧,我們來(lái)到
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
在這個(gè)方法,遍歷 BeanPostProcessors 集合并執(zhí)行每個(gè) BeanPostProcessor 的 postProcessBeforeInitialization(...) 方法。
**那么 getBeanPostProcessors() 中的內(nèi)容又是在什么時(shí)候放進(jìn)去的呢?都有哪些內(nèi)容?**可以通過(guò) AnnotationConfigUtils和 CommonAnnotationBeanPostProcessor 查找,這里就不再贅述了。
查找 applyBeanPostProcessorsBeforeInitialization(...) 的調(diào)用者,來(lái)到
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } 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()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
顧名思義,在這個(gè)方法中對(duì) Bean 進(jìn)行初始化。是在被注入前一定要經(jīng)過(guò)的過(guò)程,到這里被 @PostConstruct 標(biāo)注的方法執(zhí)行已經(jīng)完成了。至于這個(gè)方法誰(shuí)調(diào)用可以自己查看調(diào)用棧。
init-method、afterPropertiesSet() 的調(diào)用
細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn)了在 initializeBean(...) 中有調(diào)用到一個(gè)叫做 invokeInitMethods(...) 的方法。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
BeanDefinition是Bean定義的一個(gè)抽象。類(lèi)似于在Java中存在Class類(lèi)用于描述一個(gè)類(lèi),里面有你定義的 Bean 的各種信息。
在第4行,判斷是不是 InitializingBean,如果是的話(huà)會(huì)進(jìn)行類(lèi)型強(qiáng)轉(zhuǎn),然后調(diào)用 afterPropertiesSet()。
在第26行,獲得到自定義初始化方法的名字,然后在第30行調(diào)用 invokeCustomInitMethod 執(zhí)行完成。
順序的確定
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } 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()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
initializeBean(...) 方法中,先執(zhí)行 applyBeanPostProcessorsBeforeInitialization(...) 在執(zhí)行 invokeInitMethods(...) 。
而 applyBeanPostProcessorsBeforeInitialization(...) 會(huì)執(zhí)行被 @PostConstruct 標(biāo)注的方法,invokeInitMethods(...) 會(huì)執(zhí)行 afterPropertiesSet() 和自定義的初始化方法,并且 afterPropertiesSet() 在自定義的初始化方法之前執(zhí)行。
所以它們之間的執(zhí)行順序是:
@PostConstruct > afterPropertiesSet() > initMethod()
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于Intellij IDEA中的Version Control問(wèn)題
這篇文章主要介紹了Intellij IDEA中的Version Control問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-11-11SpringSecurityOAuth2 如何自定義token信息
這篇文章主要介紹了SpringSecurityOAuth2 自定義token信息的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06利用session實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車(chē)功能
這篇文章主要為大家詳細(xì)介紹了利用session實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車(chē)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02Java8 LocalDateTime極簡(jiǎn)時(shí)間日期操作小結(jié)
這篇文章主要介紹了Java8-LocalDateTime極簡(jiǎn)時(shí)間日期操作整理,通過(guò)實(shí)例代碼給大家介紹了java8 LocalDateTime 格式化問(wèn)題,需要的朋友可以參考下2020-04-04java 中序列化NotSerializableException問(wèn)題解決辦法
這篇文章主要介紹了java 中序列化NotSerializableException問(wèn)題解決辦法的相關(guān)資料,這里對(duì)序列化問(wèn)題進(jìn)行描述說(shuō)明,并提供解決辦法,希望能幫助到大家,需要的朋友可以參考下2017-08-08Flyway詳解及Springboot集成Flyway的詳細(xì)教程
Flayway是一款數(shù)據(jù)庫(kù)版本控制管理工具,,支持?jǐn)?shù)據(jù)庫(kù)版本自動(dòng)升級(jí),Migrations可以寫(xiě)成sql腳本,也可以寫(xiě)在java代碼里。這篇文章主要介紹了Flyway詳解及Springboot集成Flyway的詳細(xì)教程的相關(guān)資料,需要的朋友可以參考下2020-07-07java的if else語(yǔ)句入門(mén)指南(推薦)
下面小編就為大家?guī)?lái)一篇java的if else語(yǔ)句入門(mén)指南(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06