寫在前面
在前面的文章中,咱們講述了BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法在bean初始化的先後調用,咱們能夠自定義類來實現BeanPostProcessor接口,並在postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法中指定咱們自定義的邏輯。今天,咱們來一塊兒探討下eanPostProcessor底層原理。java
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotationgit
bean的初始化和銷燬
咱們知道BeanPostProcessor的postProcessBeforeInitialization()方法在bean的初始化以前調用;而postProcessAfterInitialization()方法在bean初始化的以後調用。而bean的初始化和銷燬方法咱們能夠經過以下方式進行指定。github
1.經過@Bean指定init-method和destroy-method
@Bean(initMethod="init",destroyMethod="detory") public Car car(){ return new Car(); }
2.經過讓Bean實現InitializingBean(定義初始化邏輯)
@Component public class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..."); } @Override public void destroy() throws Exception { System.out.println("cat...destroy..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("cat...afterPropertiesSet..."); } }
3.能夠使用JSR250
- @PostConstruct:在bean建立完成而且屬性賦值完成;來執行初始化方法。
- @PreDestroy:在容器銷燬bean以前通知咱們進行清理工做。
@Component public class Dog implements ApplicationContextAware { //@Autowired private ApplicationContext applicationContext; public Dog(){ System.out.println("dog constructor..."); } //對象建立並賦值以後調用 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除對象以前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
4.能夠使用BeanPostProcessor
/** * 後置處理器:初始化先後進行處理工做 * 將後置處理器加入到容器中 * 在bean初始化先後進行一些處理工做; * postProcessBeforeInitialization:在初始化以前工做 * postProcessAfterInitialization:在初始化以後工做 */ @Component public class MyBeanPostProcessor implements BeanPostProcessor,Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean); return bean; } @Override public int getOrder() { return 3; } }
經過這幾種方式,咱們就能夠對bean的整個生命週期進行控制:spring
- 從bean的實例化:調用bean的構造方法,咱們能夠在bean的無參構造方法中執行相應的邏輯。
- bean的初始化:在初始化時,能夠經過BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法進行攔截,執行自定義的邏輯;經過@PostConstruct註解、InitializingBean和init-method來指定bean初始化先後執行的方法,執行自定義的邏輯。
- bean的銷燬:能夠經過@PreDestroy註解、DisposableBean和destroy-method來指定bean在銷燬前執行的方法,指執行自定義的邏輯。
因此,經過上述方式,咱們能夠控制Spring中bean的整個生命週期。微信
BeanPostProcessor源碼解析
若是想深入理解BeanPostProcessor的工做原理,那就不得不看下相關的源碼,咱們能夠在MyBeanPostProcessor類的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法中打上斷點來進行調試。以下所示。app
隨後,咱們以Debug的方式來運行BeanLifeCircleTest類的testBeanLifeCircle04()方法,運行後的效果以下所示。
ide
能夠看到,程序已經運行到MyBeanPostProcessor類的postProcessBeforeInitialization()方法中,在IDEA的左下角咱們能夠清晰的看到方法的調用棧,以下所示。post
經過這個方法調用棧,咱們能夠詳細的分析從運行BeanLifeCircleTest類的testBeanLifeCircle04()方法開始,到進入MyBeanPostProcessor類的postProcessBeforeInitialization()方法的執行流程。只要咱們在IDEA的方法調用棧中找到BeanLifeCircleTest類的testBeanLifeCircle04()方法,依次分析方法調用棧中在BeanLifeCircleTest類的testBeanLifeCircle04()方法上面位置的方法,便可瞭解整個方法調用棧的過程。要想定位方法調用棧中的方法,只須要在IDEA的方法調用棧中單擊相應的方法便可。學習
注意:方法調用棧是先進後出的,也就是說,最早調用的方法會最後退出,每調用一個方法,JVM會將當前調用的方法放入棧的棧頂,方法退出時,會將方法從棧頂的位置彈出。有關方法調用的具體細節內容,後續會在【JVM】專欄詳細介紹,這裏,小夥伴們就先了解到此便可。this
接下來,咱們在IDEA的方法調用棧中,找到BeanLifeCircleTest類的testBeanLifeCircle04()方法並單擊,此時IDEA的主界面會定位到BeanLifeCircleTest類的testBeanLifeCircle04()方法,以下所示。
在BeanLifeCircleTest類的testBeanLifeCircle04()方法中,首先經過new實例對象的方式建立了一個IOC容器。接下來,經過IDEA的方法調用棧繼續分析,接下來,進入的是AnnotationConfigApplicationContext類的構造方法。
在AnnotationConfigApplicationContext類的構造方法中會調用refresh()方法。咱們跟進方法調用棧,以下所示。
能夠看到,方法的執行定位到AbstractApplicationContext類的refresh()方法中的以下代碼行。
finishBeanFactoryInitialization(beanFactory);
這行代碼的做用就是:初始化全部的(非懶加載的)單實例bean對象。
咱們繼續跟進方法調用棧,以下所示。
此時,方法的執行定位到AbstractApplicationContext類的finishBeanFactoryInitialization()方法的以下代碼行。
beanFactory.preInstantiateSingletons();
這行代碼的做用一樣是:初始化全部的(非懶加載的)單實例bean。
咱們繼續跟進方法調用棧,以下所示。
能夠看到,方法的執行定位到DefaultListableBeanFactory的preInstantiateSingletons()方法的最後一個else分支調用的getBean()方法上。繼續跟進方法調用棧,以下所示。
此時方法定位到AbstractBeanFactory類中的getBean()方法中,在getBean()方法中,又調用了doGetBean()方法,經過方法調用棧咱們能夠得知方法的執行定位到AbstractBeanFactory類中的doGetBean()方法的以下代碼段。
能夠看到,在Spring內部是經過getSingleton()來獲取單實例bean的,咱們繼續跟進方法調用棧,以下所示。
此時,方法定位到了DefaultSingletonBeanRegistry了類的getSingleton()方法的以下代碼行。
singletonObject = singletonFactory.getObject();
繼續跟進方法調用棧,以下所示。
此時,方法會定位到AbstractBeanFactory類的doGetBean()方法中的以下代碼行。
return createBean(beanName, mbd, args);
也就是說,當第一次獲取單實例bean時,因爲單實例bean還未建立,Spring會調用createBean()方法來建立單實例bean。繼續跟進方法調用棧,以下所示。
能夠看到,方法的執行定位到AbstractAutowireCapableBeanFactory類的createBean()方法的以下代碼行。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
能夠看到,Spring中建立單實例bean調用的是doCreateBean()方法。沒錯,繼續跟進方法調用棧,以下所示。
方法的執行已經定位到AbstractAutowireCapableBeanFactory類的doCreateBean()方法的以下代碼行。
exposedObject = initializeBean(beanName, exposedObject, mbd);
繼續跟進方法調用棧,以下所示。
方法的執行定位到AbstractAutowireCapableBeanFactory類的initializeBean()方法的以下代碼行。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
小夥伴們須要重點留意一下這個applyBeanPostProcessorsBeforeInitialization()方法。回過頭來咱們再來看AbstractAutowireCapableBeanFactory類的doCreateBean()方法中的以下代碼行。
exposedObject = initializeBean(beanName, exposedObject, mbd);
沒錯,在AbstractAutowireCapableBeanFactory類的doCreateBean()方法中調用的initializeBean()方法中調用了後置處理器的邏輯。小夥伴們須要注意一下,在AbstractAutowireCapableBeanFactory類的doCreateBean()方法中調用的initializeBean()方法以前,調用了一個populateBean()方法,代碼行以下所示。
populateBean(beanName, mbd, instanceWrapper);
咱們點到這個populateBean()方法中,看下這個方法執行了哪些邏輯,以下所示。
populateBean()方法一樣是AbstractAutowireCapableBeanFactory類中的方法,populateBean()方法的代碼比較多,其實邏輯很是簡單,populateBean()方法作的工做就是爲bean的屬性賦值。也就是說,在Spring中會先調用populateBean()方法爲屬性賦好值,而後再調用initializeBean()方法。接下來,咱們好好分析下initializeBean()方法,爲了方便,我將Spring中AbstractAutowireCapableBeanFactory類的initializeBean()方法的代碼拿出來,以下所示。
protected Object initializeBean(final String beanName, final 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()方法中,調用了invokeInitMethods()方法,代碼行以下所示。
invokeInitMethods(beanName, wrappedBean, mbd);
invokeInitMethods()方法的做用就是:執行初始化方法,這些初始化方法包括咱們以前講的: 在xml文件中的標籤中使用init-method屬性指定的初始化方法;在@Bean註解中使用initMehod屬性指定的方法;使用@PostConstruct註解標註的方法;實現InitializingBean接口的方法等。
在調用invokeInitMethods()方法以前,Spring調用了applyBeanPostProcessorsBeforeInitialization()方法,代碼行以下所示。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
在調用invokeInitMethods()方法以後,Spring調用了applyBeanPostProcessorsAfterInitialization()方法,以下所示。
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
這裏,咱們先來看看applyBeanPostProcessorsBeforeInitialization()方法中具體執行了哪些邏輯,applyBeanPostProcessorsBeforeInitialization()方法位於AbstractAutowireCapableBeanFactory類中,源碼以下所示。
@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; }
能夠看到,在applyBeanPostProcessorsBeforeInitialization()方法中,會遍歷全部BeanPostProcessor對象,執行全部BeanPostProcessor對象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor對象的postProcessBeforeInitialization()方法返回null,則後面的BeanPostProcessor對象再也不執行,直接退出for循環。
看Spring源碼,咱們看到一個細節, 在Spring中調用initializeBean()方法以前,調用了populateBean()方法來爲bean的屬性賦值。
咱們將關鍵代碼的調用過程使用以下僞代碼表述出來。
populateBean(beanName, mbd, instanceWrapper); initializeBean(beanName, exposedObject, mbd){ applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
也就是說,在Spring中,調用initializeBean()方法以前,調用了populateBean()方法爲bean的屬性賦值,爲bean的屬性賦好值以後,再調用initializeBean()方法進行初始化。
在initializeBean()中,調用自定義的初始化方法invokeInitMethods()以前,調用了applyBeanPostProcessorsBeforeInitialization()方法,而在調用自定義的初始化方法invokeInitMethods()以後,調用了applyBeanPostProcessorsAfterInitialization()方法。整個bean的初始化過程就結束了。
好了,我們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一塊兒學習一塊兒進步!!
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
寫在最後
若是以爲文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習Spring註解驅動開發。公衆號回覆「spring註解」關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發再也不迷茫。