最近,不少小夥伴出去面試都被問到了Spring問題,關於Spring,細節點不少,面試官也很是喜歡問一些很細節的技術點。因此,在 Spring 專題中,咱們儘可能把Spring的每一個技術細節說清楚,將透徹。java
關注 冰河技術 微信公衆號,回覆 「 Spring註解 」 關鍵字領取源碼。面試
若是文章對你有所幫助,歡迎你們留言、點贊、在看和轉發,你們的支持是我持續創做的動力!spring
自定義組件要想使用Spring容器底層的一些組件(好比:ApplicationContext、BeanFactory等),此時,只須要讓自定義組件實現XxxAware接口便可。此時,Spring在建立對象的時候,會調用XxxAware接口定義的方法,注入相關的組件。設計模式
其實,咱們以前使用過XxxAware接口,例如,咱們以前建立的Employee類,就實現了ApplicationContextAware接口,Employee類的源碼以下所示。bash
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author binghe * @version 1.0.0 * @description 測試ApplicationContextAware */ @Component public class Employee implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
從Employee類的源碼能夠看出,實現ApplicationContextAware接口的話,須要實現setApplicationContext()方法。在IOC容器啓動並建立Employee對象時,Spring會調用setApplicationContext()方法,而且會將ApplicationContext對象傳入到setApplicationContext()方法中,咱們只須要在Employee類中定義一個ApplicationContext類型的成員變量來接收setApplicationContext()方法的參數,就可使用ApplicationContext對象了。微信
其實,在Spring中,相似於ApplicationContextAware接口的設計有不少,本質上,Spring中相似XxxAware接口都繼承了Aware接口,咱們來看下Aware接口的源碼,以下所示。併發
package org.springframework.beans.factory; /** * @author Chris Beams * @author Juergen Hoeller * @since 3.1 */ public interface Aware { }
能夠看到,Aware接口是Spring 3.1版本中引入的接口,在Aware接口中,並未定義任何方法。app
接下來,咱們看看都有哪些接口繼承了Aware接口,以下所示。分佈式
接下來,咱們就挑選幾個經常使用的XxxAware接口來進行簡單的說明。ide
ApplicationContextAware接口使用的比較多,咱們先來講說這個接口,經過ApplicationContextAware接口咱們能夠獲取到IOC容器。
首先,咱們建立一個Blue類,並實現ApplicationContextAware接口,在實現的setApplicationContext()中將ApplicationContext輸出,以下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * @author binghe * @version 1.0.0 * @description 測試ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware { private ApplicationContext applicationContext @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("傳入的ioc:" + applicationContext); this.applicationContext = applicationContext; } }
咱們也能夠爲Blue類同時實現幾個XxxAware接口,例如,使Blue類再實現一個BeanNameAware接口,咱們能夠經過BeanNameAware接口獲取到當前bean在Spring容器中的名稱,以下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * @author binghe * @version 1.0.0 * @description 測試ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware, BeanNameAware { private ApplicationContext applicationContext @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("傳入的ioc:" + applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { System.out.println("當前bean的名字"); } }
接下來,咱們再實現一個EmbeddedValueResolverAware接口,咱們經過EmbeddedValueResolverAware接口可以獲取到StringValue解析器。以下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringValueResolver; /** * @author binghe * @version 1.0.0 * @description 測試ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("傳入的ioc:" + applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { System.out.println("當前bean的名字"); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String resolveStringValue = resolver.resolveStringValue("你好${os.name} 年齡:#{20*18}"); System.out.println("解析後的字符串爲:" + resolveStringValue); } }
接下來,咱們須要在Blue類上標註@Component註解將Blue類添加到IOC容器中,以下所示。
@Component public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
運行AutowiredTest類的testAutowired02()方法,輸出的結果信息以下所示。
postProcessBeforeInitialization...autowiredConfig=>io.mykit.spring.plugins.register.config.AutowiredConfig$$EnhancerBySpringCGLIB$$d3c83622@1c93084c postProcessAfterInitialization...autowiredConfig=>io.mykit.spring.plugins.register.config.AutowiredConfig$$EnhancerBySpringCGLIB$$d3c83622@1c93084c postProcessBeforeInitialization...personDao=>PersonDao{remark='1'} postProcessAfterInitialization...personDao=>PersonDao{remark='1'} postProcessBeforeInitialization...personDao2=>PersonDao{remark='2'} postProcessAfterInitialization...personDao2=>PersonDao{remark='2'} postProcessBeforeInitialization...personService=>PersonService{personDao=PersonDao{remark='2'}} postProcessAfterInitialization...personService=>PersonService{personDao=PersonDao{remark='2'}} postProcessBeforeInitialization...personController=>io.mykit.spring.plugins.register.controller.PersonController@48ae9b55 postProcessAfterInitialization...personController=>io.mykit.spring.plugins.register.controller.PersonController@48ae9b55 執行了Animal類的無參數構造方法 postProcessBeforeInitialization...animal=>io.mykit.spring.plugins.register.bean.Animal@c267ef4 執行了Animal類的初始化方法。。。。。 postProcessAfterInitialization...animal=>io.mykit.spring.plugins.register.bean.Animal@c267ef4 當前bean的名字:blue 解析後的字符串爲:你好Windows 10 年齡:360 傳入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f, started on Wed Aug 19 00:10:13 CST 2020 postProcessBeforeInitialization...blue=>io.mykit.spring.plugins.register.bean.Blue@55182842 postProcessAfterInitialization...blue=>io.mykit.spring.plugins.register.bean.Blue@55182842 Cat類的構造方法... postProcessBeforeInitialization...cat=>io.mykit.spring.plugins.register.bean.Cat@76505305 Cat的postConstruct()方法... postProcessAfterInitialization...cat=>io.mykit.spring.plugins.register.bean.Cat@76505305 調用了Dog的有參構造方法 postProcessBeforeInitialization...dog=>Dog{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessAfterInitialization...dog=>Dog{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessBeforeInitialization...employee=>io.mykit.spring.plugins.register.bean.Employee@74235045 postProcessAfterInitialization...employee=>io.mykit.spring.plugins.register.bean.Employee@74235045 postProcessBeforeInitialization...fish=>Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessAfterInitialization...fish=>Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} Cat的preDestroy()方法... 執行了Animal類的銷燬方法。。。。。
輸出結果中有以下信息。
當前bean的名字:blue 解析後的字符串爲:你好Windows 10 年齡:360 傳入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f, started on Wed Aug 19 00:10:13 CST 2020
說明正確的輸出告終果信息。
XxxAware的底層原理是由XxxAwareProcessor類實現的, 例如,咱們這裏以ApplicationContextAware接口爲例,ApplicationContextAware接口的底層原理就是由ApplicationContextAwareProcessor類實現的。從ApplicationContextAwareProcessor類的源碼能夠看出,其實現了BeanPostProcessor接口,本質上都是後置處理器。
class ApplicationContextAwareProcessor implements BeanPostProcessor
接下來,咱們就以分析ApplicationContextAware接口的原理爲例,看看Spring是怎麼將ApplicationContext對象注入到Blue類中的。
咱們在Blue類的setApplicationContext()方法上打一個斷點,以下所示。
接下來,咱們以debug的方式來運行AutowiredTest類的testAutowired02()方法,
這裏,咱們能夠看到,實際上ApplicationContext對象已經注入到Blue類中的setApplicationContext()方法中了。咱們在IDEA的方法調用棧中選擇postProcessBeforeInitialization()方法,以下所示。
咱們雙擊IDEA中的postProcessBeforeInitialization()方法的調用棧,會在IDEA中自動定位到postProcessBeforeInitialization()方法中,以下所示。
其實,postProcessBeforeInitialization()方法所在的類就是ApplicationContextAwareProcessor。postProcessBeforeInitialization()方法的邏輯比較簡單。
咱們來看下在postProcessBeforeInitialization()方法中調用的invokeAwareInterfaces()方法,以下所示。
看到這裏,你們是否是有種豁然開朗的感受!Blue類實現了ApplicationContextAware接口後,Spring爲啥會將ApplicationContext對象自動注入到setApplicationContext()方法中就不用說了吧!
其實就是這麼簡單!
關注「 冰河技術 」微信公衆號,後臺回覆 「設計模式」 關鍵字領取《深刻淺出Java 23種設計模式》PDF文檔。回覆「Java8」關鍵字領取《Java8新特性教程》PDF文檔。回覆「限流」關鍵字獲取《億級流量下的分佈式限流解決方案》PDF文檔,三本PDF均是由冰河原創並整理的超硬核教程,面試必備!!
好了,今天就聊到這兒吧!別忘了點個贊,給個在看和轉發,讓更多的人看到,一塊兒學習,一塊兒進步!!
若是你以爲冰河寫的還不錯,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習高併發、分佈式、微服務、大數據、互聯網和雲原生技術,「 冰河技術 」微信公衆號更新了大量技術專題,每一篇技術文章乾貨滿滿!很多讀者已經經過閱讀「 冰河技術 」微信公衆號文章,吊打面試官,成功跳槽到大廠;也有很多讀者實現了技術上的飛躍,成爲公司的技術骨幹!若是你也想像他們同樣提高本身的能力,實現技術能力的飛躍,進大廠,升職加薪,那就關注「 冰河技術 」微信公衆號吧,天天更新超硬核技術乾貨,讓你對如何提高技術能力再也不迷茫!