本篇文章是「Spring IOC 容器源碼分析」系列文章的最後一篇文章,本篇文章所分析的對象是 initializeBean 方法,該方法用於對已完成屬性填充的 bean 作最後的初始化工做。相較於以前幾篇文章所分析的源碼,initializeBean 的源碼相對比較簡單,你們能夠愉快的閱讀。好了,其餘的很少說了,咱們直入主題吧。java
本章咱們來分析一下 initializeBean 方法的源碼。在完成分析後,仍是像往常同樣,把方法的執行流程列出來。好了,看源碼吧:app
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { // 若 bean 實現了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 等接口,則向 bean 中注入相關對象 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 執行 bean 初始化前置操做 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { /* * 調用初始化方法: * 1. 若 bean 實現了 InitializingBean 接口,則調用 afterPropertiesSet 方法 * 2. 若用戶配置了 bean 的 init-method 屬性,則調用用戶在配置中指定的方法 */ 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()) { // 執行 bean 初始化後置操做,AOP 會在此處向目標對象中織入切面邏輯 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
以上就是 initializeBean 方法的邏輯,很簡單是否是。該方法作了以下幾件事情:ide
在上面的流程中,咱們又發現了後置處理器的蹤跡。若是你們閱讀過 Spring 的源碼,會發現後置處理器在 Spring 源碼中屢次出現過。後置處理器是 Spring 拓展點之一,經過實現後置處理器 BeanPostProcessor 接口,咱們就能夠插手 bean 的初始化過程。好比你們所熟悉的 AOP 就是在後置處理 postProcessAfterInitialization 方法中向目標對象中織如切面邏輯的。關於「前置處理」和「後置處理」相關的源碼,這裏就不分析了,你們有興趣本身去看一下。接下來分析一下 invokeAwareMethods 和 invokeInitMethods 方法,以下:源碼分析
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { // 注入 beanName 字符串 ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { // 注入 ClassLoader 對象 ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } if (bean instanceof BeanFactoryAware) { // 注入 BeanFactory 對象 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
invokeAwareMethods 方法的邏輯很簡單,一句話總結:根據 bean 所實現的 Aware 的類型,向 bean 中注入不一樣類型的對象。post
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { // 檢測 bean 是不是 InitializingBean 類型的 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 若是 bean 實現了 InitializingBean,則調用 afterPropertiesSet 方法執行初始化邏輯 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // 調用用戶自定義的初始化方法 invokeCustomInitMethod(beanName, bean, mbd); } } }
invokeInitMethods 方法用於執行初始化方法,也不復雜,就很少說了。this
本篇文章到這裏差很少就分析完了,總的來講本文的內容比較簡單,很容易看懂。正如簡介一章中所說,本篇文章是個人「Spring IOC 容器源碼分析」系列文章的最後一篇文章。寫完這本篇文章,有種如釋重負的感受。我在5月15號寫完 Java CAS 原理分析 文章後,第二天開始閱讀 Spring IOC 部分的源碼,閱讀該部分源碼花了大概兩週的時間。而後在5月30號發佈了「Spring IOC 容器源碼分析」系列文章的第一篇文章 Spring IOC 容器源碼分析系列文章導讀。在寫完第一篇文章後,就開啓了快速更新模式,以平均2天一篇的速度進行更新。終於在今天,也就是6月11號寫完了最後一篇。這一段時間寫文章寫的很累,常常熬夜。主要的緣由在於,在本身看懂源碼的同時,經過寫文章的方式儘可能保證別人也能看懂的話,這個就比較難了。好比我在閱讀源碼的時候,在源碼上面寫了一些簡單的註釋。這些註釋我能夠看懂,但若是想寫成文章,則須要把註釋寫的儘可能詳細,必要的背景知識也要介紹一下。總的來講,認真寫一篇技術文章仍是不容易的。寫文章尚如此,那寫書呢,想必更加辛苦了。我在閱讀源碼和寫文章的過程當中,也參考了一些資料(相關資料在「導讀」一文中指明瞭出處,本文就再也不次說明)。在這裏,向這些資料的做者表示感謝!spa
好了,本篇文章就到這裏了,感謝你們的閱讀。debug
本文在知識共享許可協議 4.0 下發布,轉載需在明顯位置處註明出處
做者:coolblog.xyz
本文同步發佈在個人我的博客: http://www.coolblog.xyz
更新時間 | 標題 |
---|---|
2018-05-30 | Spring IOC 容器源碼分析系列文章導讀 |
2018-06-01 | Spring IOC 容器源碼分析 - 獲取單例 bean |
2018-06-04 | Spring IOC 容器源碼分析 - 建立單例 bean 的過程 |
2018-06-06 | Spring IOC 容器源碼分析 - 建立原始 bean 對象 |
2018-06-08 | Spring IOC 容器源碼分析 - 循環依賴的解決辦法 |
2018-06-11 | Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對象 |
2018-06-11 | Spring IOC 容器源碼分析 - 餘下的初始化工做 |
更新時間 | 標題 |
---|---|
2018-06-17 | Spring AOP 源碼分析系列文章導讀 |
2018-06-20 | Spring AOP 源碼分析 - 篩選合適的通知器 |
2018-06-20 | Spring AOP 源碼分析 - 建立代理對象 |
2018-06-22 | Spring AOP 源碼分析 - 攔截器鏈的執行過程 |
更新時間 | 標題 |
---|---|
2018-06-29 | Spring MVC 原理探祕 - 一個請求的旅行過程 |
2018-06-30 | Spring MVC 原理探祕 - 容器的建立過程 |
本做品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。代理