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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

javascript

自己动手实现的 Spring IOC 和 AOP - 下篇

發(fā)布時(shí)間:2025/3/21 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己动手实现的 Spring IOC 和 AOP - 下篇 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. 背景

本文承接上文,來(lái)繼續(xù)說(shuō)說(shuō) IOC 和 AOP 的仿寫(xiě)。在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的 IOC 和 AOP 容器。上文實(shí)現(xiàn)的 IOC 和 AOP 功能很單一,且 IOC 和 AOP 兩個(gè)模塊沒(méi)有整合到一起。IOC 在加載 bean 過(guò)程中,AOP 不能對(duì) bean 織入通知。在本文中,我們?cè)敿?xì)說(shuō)一下升級(jí)版 IOC 和 AOP。這個(gè)版本的實(shí)現(xiàn)包含了在上篇中所說(shuō)的功能,這里再重述一下,如下:

  • 根據(jù) xml 配置文件加載相關(guān) bean
  • 對(duì) BeanPostProcessor 類型的 bean 提供支持
  • 對(duì) BeanFactoryAware 類型的 bean 提供支持
  • 實(shí)現(xiàn)了基于 JDK 動(dòng)態(tài)代理的 AOP
  • 整合了 IOC 和 AOP,使得二者可很好的協(xié)同工作
  • 上面羅列了5個(gè)功能點(diǎn),雖然看起來(lái)不多,但是對(duì)于新手來(lái)說(shuō),實(shí)現(xiàn)起來(lái)還是不很容易的。所以接下來(lái),我將圍繞上面的功能點(diǎn)展開(kāi)詳細(xì)的描述。如果大家有興趣,我還是很建議大家跟著寫(xiě)一遍,因?yàn)楹芏鄷r(shí)候能看懂,但是寫(xiě)的卻不一定能寫(xiě)出來(lái)。仿寫(xiě)一遍能夠加深對(duì) Spring IOC 和 AOP 原理的理解,多動(dòng)手是有好處的。

    另外需要說(shuō)明的是,黃億華前輩實(shí)現(xiàn)的?tiny-spring?項(xiàng)目時(shí)間節(jié)點(diǎn)是 2014.1,當(dāng)時(shí)應(yīng)該是參照 Spring 3.x 版本編寫(xiě)的。部分類的設(shè)計(jì)思想可能會(huì)與現(xiàn)在最新穩(wěn)定版 4.3.10 有一定的出入,由于我暫時(shí)沒(méi)有閱讀 Spring 源碼的計(jì)劃,所以這里不能告知大家?tiny-spring?哪些類與 Spring 最新的源碼有出入,見(jiàn)諒。

    好了,本章內(nèi)容先介紹到這,接下來(lái)進(jìn)入正文。

    ?2. IOC 的實(shí)現(xiàn)

    ?2.1 BeanFactory 的生命流程

    上面簡(jiǎn)述了 toy-spring 項(xiàng)目的編碼背景,接下來(lái),在本節(jié)中,我將向大家介紹 toy-spring 項(xiàng)目中 IOC 部分的實(shí)現(xiàn)原理。在詳細(xì)介紹 IOC 的實(shí)現(xiàn)原理前,這里先簡(jiǎn)單說(shuō)一下 BeanFactory 的生命流程:

  • BeanFactory 加載 Bean 配置文件,將讀到的 Bean 配置封裝成 BeanDefinition 對(duì)象
  • 將封裝好的 BeanDefinition 對(duì)象注冊(cè)到 BeanDefinition 容器中
  • 注冊(cè) BeanPostProcessor 相關(guān)實(shí)現(xiàn)類到 BeanPostProcessor 容器中
  • BeanFactory 進(jìn)入就緒狀態(tài)
  • 外部調(diào)用 BeanFactory 的 getBean(String name) 方法,BeanFactory 著手實(shí)例化相應(yīng)的 bean
  • 重復(fù)步驟 3 和 4,直至程序退出,BeanFactory 被銷(xiāo)毀
  • 上面簡(jiǎn)單羅列了 BeanFactory 的生命流程,也就是 IOC 容器的生命流程。接下來(lái)就來(lái)圍繞上面的流程展開(kāi)討論。

    ?2.2 BeanDefinition 及其他一些類的介紹

    在詳細(xì)介紹 IOC 容器的工作原理前,這里先介紹一下實(shí)現(xiàn) IOC 所用到的一些輔助類,包括BeanDefinition、BeanReference、PropertyValues、PropertyValue。這些類與接下來(lái)的 2.3 節(jié) xml 的解析緊密相關(guān)。按照順序,先從 BeanDefinition 開(kāi)始介紹。

    BeanDefinition,從字面意思上翻譯成中文就是 “Bean 的定義”。從翻譯結(jié)果中就可以猜出這個(gè)類的用途,即根據(jù) Bean 配置信息生成相應(yīng)的 Bean 詳情對(duì)象。舉個(gè)例子,如果把 Bean 比作是電腦 ?,那么 BeanDefinition 就是這臺(tái)電腦的配置清單。我們從外觀上無(wú)法看出這臺(tái)電腦里面都有哪些配置,也看不出電腦的性能咋樣。但是通過(guò)配置清單,我們就可了解這臺(tái)電腦的詳細(xì)配置。我們可以知道這臺(tái)電腦是不是用了牙膏廠的 CPU,BOOM 廠的固態(tài)硬盤(pán)等。透過(guò)配置清單,我們也就可大致評(píng)估出這臺(tái)電腦的性能。

    圖1 電腦和配置清單

    上面那個(gè)例子還是比較貼切的,但是只是個(gè)例子,和實(shí)際還是有差距的。那么在具體實(shí)現(xiàn)中,BeanDefinition 和 xml 是怎么對(duì)應(yīng)的呢?答案在下面:

    圖2 根據(jù) bean 配置生成 BeanDefinition

    看完上圖,我想大家對(duì) BeanDefinition 的用途有了更進(jìn)一步的認(rèn)識(shí)。接下來(lái)我們來(lái)說(shuō)說(shuō)上圖中的 ref 對(duì)應(yīng)的 BeanReference 對(duì)象。BeanReference 對(duì)象保存的是 bean 配置中 ref 屬性對(duì)應(yīng)的值,在后續(xù) BeanFactory 實(shí)例化 bean 時(shí),會(huì)根據(jù) BeanReference 保存的值去實(shí)例化 bean 所依賴的其他 bean。

    接下來(lái)說(shuō)說(shuō) PropertyValues 和 PropertyValue 這兩個(gè)長(zhǎng)的比較像的類,首先是PropertyValue。PropertyValue 中有兩個(gè)字段 name 和 value,用于記錄 bean 配置中的標(biāo)簽的屬性值。然后是PropertyValues,PropertyValues 從字面意思上來(lái)看,是 PropertyValue 復(fù)數(shù)形式,在功能上等同于 List。那么為什么 Spring 不直接使用 List,而自己定義一個(gè)新類呢?答案是要獲得一定的控制權(quán),看下面的代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class PropertyValues {private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();public void addPropertyValue(PropertyValue pv) {// 在這里可以對(duì)參數(shù)值 pv 做一些處理,如果直接使用 List,則就不行了this.propertyValueList.add(pv);}public List<PropertyValue> getPropertyValues() {return this.propertyValueList;}}

    好了,輔助類介紹完了,接下來(lái)我們繼續(xù) BeanFactory 的生命流程探索。

    ?2.3 xml 的解析

    BeanFactory 初始化時(shí),會(huì)根據(jù)傳入的 xml 配置文件路徑加載并解析配置文件。但是加載和解析 xml 配置文件這種臟活累活,BeanFactory 可不太愿意干,它只想高冷的管理容器中的 bean。于是 BeanFactory 將加載和解析配置文件的任務(wù)委托給專職人員 BeanDefinitionReader 的實(shí)現(xiàn)類 XmlBeanDefinitionReader 去做。那么 XmlBeanDefinitionReader 具體是怎么做的呢?XmlBeanDefinitionReader 做了如下幾件事情:

  • 將 xml 配置文件加載到內(nèi)存中
  • 獲取根標(biāo)簽下所有的標(biāo)簽
  • 遍歷獲取到的標(biāo)簽列表,并從標(biāo)簽中讀取 id,class 屬性
  • 創(chuàng)建 BeanDefinition 對(duì)象,并將剛剛讀取到的 id,class 屬性值保存到對(duì)象中
  • 遍歷標(biāo)簽下的標(biāo)簽,從中讀取屬性值,并保持在 BeanDefinition 對(duì)象中
  • 將 <id, BeanDefinition> 鍵值對(duì)緩存在 Map 中,留作后用
  • 重復(fù)3、4、5、6步,直至解析結(jié)束
  • 上面的解析步驟并不復(fù)雜,實(shí)現(xiàn)起來(lái)也不難,就是解析 xml 而已,這里就不過(guò)多敘述了。

    ?2.4 注冊(cè) BeanPostProcessor

    BeanPostProcessor 接口是 Spring 對(duì)外拓展的接口之一,其主要用途提供一個(gè)機(jī)會(huì),讓開(kāi)發(fā)人員能夠插手 bean 的實(shí)例化過(guò)程。通過(guò)實(shí)現(xiàn)這個(gè)接口,我們就可在 bean 實(shí)例化時(shí),對(duì)bean 進(jìn)行一些處理。比如,我們所熟悉的 AOP 就是在這里將切面邏輯織入相關(guān) bean 中的。正是因?yàn)橛辛?BeanPostProcessor 接口作為橋梁,才使得 AOP 可以和 IOC 容器產(chǎn)生聯(lián)系。關(guān)于這一點(diǎn),我將會(huì)在后續(xù)章節(jié)詳細(xì)說(shuō)明。

    接下來(lái)說(shuō)說(shuō) BeanFactory 是怎么注冊(cè) BeanPostProcessor 相關(guān)實(shí)現(xiàn)類的。

    XmlBeanDefinitionReader 在完成解析工作后,BeanFactory 會(huì)將它解析得到的 <id, BeanDefinition> 鍵值對(duì)注冊(cè)到自己的 beanDefinitionMap 中。BeanFactory 注冊(cè)好 BeanDefinition 后,就立即開(kāi)始注冊(cè) BeanPostProcessor 相關(guān)實(shí)現(xiàn)類。這個(gè)過(guò)程比較簡(jiǎn)單:

  • 根據(jù) BeanDefinition 記錄的信息,尋找所有實(shí)現(xiàn)了 BeanPostProcessor 接口的類。
  • 實(shí)例化 BeanPostProcessor 接口的實(shí)現(xiàn)類
  • 將實(shí)例化好的對(duì)象放入 List中
  • 重復(fù)2、3步,直至所有的實(shí)現(xiàn)類完成注冊(cè)
  • 上面簡(jiǎn)述了 BeanPostProcessor 接口的用途以及注冊(cè)的過(guò)程。BeanPostProcessor 是一個(gè)比較常用接口,相信大家都很熟悉了,這里就不過(guò)多敘述了。

    ?2.5 getBean 過(guò)程解析

    在完成了 xml 的解析、BeanDefinition 的注冊(cè)以及 BeanPostProcessor 的注冊(cè)過(guò)程后。BeanFactory 初始化的工作算是結(jié)束了,此時(shí) BeanFactory 處于就緒狀態(tài),等待外部程序的調(diào)用。

    外部程序一般都是通過(guò)調(diào)用 BeanFactory 的 getBean(String name) 方法來(lái)獲取容器中的 bean。BeanFactory 具有延遲實(shí)例化 bean 的特性,也就是等外部程序需要的時(shí)候,才實(shí)例化相關(guān)的 bean。這樣做的好處是比較顯而易見(jiàn)的,第一是提高了 BeanFactory 的初始化速度,第二是節(jié)省了內(nèi)存資源。下面我們就來(lái)詳細(xì)說(shuō)說(shuō) bean 的實(shí)例化過(guò)程:

    圖3 Spring bean實(shí)例化過(guò)程

    上圖是一個(gè)完整的 Spring bean 實(shí)例化過(guò)程圖。在我的仿寫(xiě)項(xiàng)目中,沒(méi)有做的這么復(fù)雜,簡(jiǎn)化了 bean 實(shí)例化的過(guò)程,如下:

    圖4 toy-spring bean實(shí)例化過(guò)程

    接下來(lái)我將按照簡(jiǎn)化后的 bean 實(shí)例化過(guò)程介紹,如果想了解完整的 bean 實(shí)例化過(guò)程,可以參考我的另一篇文章:Spring bean的生命流程。簡(jiǎn)化后的實(shí)例化流程如下:

  • 實(shí)例化 bean 對(duì)象,類似于 new XXObject()
  • 將配置文件中配置的屬性填充到剛剛創(chuàng)建的 bean 對(duì)象中
  • 檢查 bean 對(duì)象是否實(shí)現(xiàn)了 Aware 一類的接口,如果實(shí)現(xiàn)了則把相應(yīng)的依賴設(shè)置到 bean 對(duì)象中。toy-spring 目前僅對(duì) BeanFactoryAware 接口實(shí)現(xiàn)類提供了支持
  • 調(diào)用 BeanPostProcessor 前置處理方法,即 postProcessBeforeInitialization(Object bean, String beanName)
  • 調(diào)用 BeanPostProcessor 后置處理方法,即 postProcessAfterInitialization(Object bean, String beanName)
  • bean 對(duì)象處于就緒狀態(tài),可以使用了
  • 上面 6 步流程并不復(fù)雜,源碼實(shí)現(xiàn)的也較為簡(jiǎn)單,這里就不在貼代碼說(shuō)明了。大家如果想了解細(xì)節(jié),可以去 github 上下載?toy-spring?源碼閱讀。

    ?3. 實(shí)現(xiàn) AOP

    ?3.1 AOP 原理

    AOP 是基于動(dòng)態(tài)代理模式實(shí)現(xiàn)的,具體實(shí)現(xiàn)上可以基于 JDK 動(dòng)態(tài)代理或者 Cglib 動(dòng)態(tài)代理。其中 JDK 動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的對(duì)象,而 Cglib 動(dòng)態(tài)代理則無(wú)此限制。所以在為沒(méi)有實(shí)現(xiàn)接口的對(duì)象生成代理時(shí),只能使用 Cglib。在 toy-spring 項(xiàng)目中,暫時(shí)只實(shí)現(xiàn)了基于 JDK 動(dòng)態(tài)代理的代理對(duì)象生成器。

    關(guān)于 AOP 原理這里就不多說(shuō)了,下面說(shuō)說(shuō) toy-spring 中 AOP 的實(shí)現(xiàn)步驟。還是像上面一樣,先列流程:

  • AOP 邏輯介入 BeanFactory 實(shí)例化 bean 的過(guò)程
  • 根據(jù) Pointcut 定義的匹配規(guī)則,判斷當(dāng)前正在實(shí)例化的 bean 是否符合規(guī)則
  • 如果符合,代理生成器將切面邏輯 Advice 織入 bean 相關(guān)方法中,并為目標(biāo) bean 生成代理對(duì)象
  • 將生成的 bean 的代理對(duì)象返回給 BeanFactory 容器,到此,AOP 邏輯執(zhí)行結(jié)束
  • 對(duì)于上面的4步流程,熟悉 Spring AOP 的朋友應(yīng)該能很容易理解。如果有朋友不理解也沒(méi)關(guān)系,在后續(xù)章節(jié),我會(huì)詳細(xì)介紹相關(guān)流程的具體實(shí)現(xiàn)。

    ?3.2 基于 JDK 動(dòng)態(tài)代理的 AOP 實(shí)現(xiàn)

    本節(jié)說(shuō)說(shuō)基于 JDK 動(dòng)態(tài)代理的代理對(duì)象生成器具體實(shí)現(xiàn)。在 toy-spring 項(xiàng)目中,代理對(duì)象生成器的邏輯主要寫(xiě)在了 JdkDynamicAopProxy 類中,這個(gè)類的有兩個(gè)方法,其中 getProxy 方法用于生成代理對(duì)象。invoke 方法是 InvocationHandler 接口的具體實(shí)現(xiàn),包含了將通知(Advice)織入相關(guān)方法中,是3.1節(jié)所列流程中第3步流程的具體實(shí)現(xiàn)。好了,接下來(lái),對(duì)著源碼講解 JdkDynamicAopProxy:

    JdkDynamicAopProxy 實(shí)現(xiàn)代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public abstract class AbstractAopProxy implements AopProxy {protected AdvisedSupport advised;public AbstractAopProxy(AdvisedSupport advised) {this.advised = advised;} }/*** 基于 JDK 動(dòng)態(tài)代理的代理對(duì)象生成器* Created by code4wt on 17/8/16.*/ final public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {public JdkDynamicAopProxy(AdvisedSupport advised) {super(advised);}/*** 為目標(biāo) bean 生成代理對(duì)象* @return bean 的代理對(duì)象*/@Overridepublic Object getProxy() {return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this);}/*** InvocationHandler 接口中的 invoke 方法具體實(shí)現(xiàn),封裝了具體的代理邏輯* @param proxy* @param method* @param args* @return 代理方法或原方法的返回值* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodMatcher methodMatcher = advised.getMethodMatcher();// 1. 使用方法匹配器 methodMatcher 測(cè)試 bean 中原始方法 method 是否符合匹配規(guī)則if (methodMatcher != null && methodMatcher.matchers(method, advised.getTargetSource().getTargetClass())) {// 獲取 Advice。MethodInterceptor 的父接口繼承了 AdviceMethodInterceptor methodInterceptor = advised.getMethodInterceptor();/* * 2. 將 bean 的原始方法 method 封裝在 MethodInvocation 接口實(shí)現(xiàn)類對(duì)象中,* 并把生成的對(duì)象作為參數(shù)傳給 Adivce 實(shí)現(xiàn)類對(duì)象,執(zhí)行通知邏輯*/ return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));} else {// 2. 當(dāng)前 method 不符合匹配規(guī)則,直接調(diào)用 bean 的原始方法 methodreturn method.invoke(advised.getTargetSource().getTarget(), args);}} }

    上面貼的代碼,已經(jīng)對(duì) JdkDynamicAopProxy 實(shí)現(xiàn)代碼進(jìn)行了逐行介解釋,這里不再多說(shuō)。下面用個(gè)流程圖對(duì)通知織入邏輯進(jìn)行總結(jié):


    圖5 toy-spring AOP 通知織入流程圖

    最后對(duì) JdkDynamicAopProxy 進(jìn)行簡(jiǎn)單的測(cè)試,測(cè)試代碼及結(jié)果如下

    測(cè)試類:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class LogInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(invocation.getMethod().getName() + " method start");Object obj= invocation.proceed();System.out.println(invocation.getMethod().getName() + " method end");return obj;} }public class JdkDynamicAopProxyTest {@Testpublic void getProxy() throws Exception {System.out.println("---------- no proxy ----------");HelloService helloService = new HelloServiceImpl();helloService.sayHelloWorld();System.out.println("\n----------- proxy -----------");AdvisedSupport advisedSupport = new AdvisedSupport();advisedSupport.setMethodInterceptor(new LogInterceptor());TargetSource targetSource = new TargetSource(helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces());advisedSupport.setTargetSource(targetSource);advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true);helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy();helloService.sayHelloWorld();} }

    測(cè)試結(jié)果:

    為了控制文章篇幅,上面代碼中用到的其他輔助類,這里就不貼出來(lái)了,想看的朋友可以到 github 上下載源碼。

    ?3.3 AOP 與 IOC 協(xié)作

    上一節(jié)介紹了3.1節(jié)所列流程中第3步流程的具體實(shí)現(xiàn),這一節(jié)則會(huì)介紹1、2、4步流程的具體實(shí)現(xiàn)。在介紹之前,還要再次提一下 BeanPostProcessor接口。在之前2.4節(jié) 注冊(cè) BeanPostProcessor 中我已經(jīng)介紹過(guò) BeanPostProcessor 的作用,也說(shuō)到了 AOP 是通過(guò) BeanPostProcessor 接口與 IOC 產(chǎn)生聯(lián)系的。不過(guò)2.4節(jié),只是蜻蜓點(diǎn)水提了一下,沒(méi)有詳細(xì)展開(kāi)說(shuō)明。在本節(jié)中,我將詳細(xì)講解 toy-spring 項(xiàng)目中 AOP 和 IOC 是怎樣被整合到一起的。

    Spring 從2.0版本開(kāi)始集成 AspectJ,通過(guò)集成 AspectJ,也使得 Spring AOP 的功能得到了很大的增強(qiáng)。我們?cè)谄綍r(shí)開(kāi)發(fā)中,很多時(shí)候是使用基于 AspectJ 表達(dá)式及其他配置來(lái)實(shí)現(xiàn)切面功能。所以我在編寫(xiě) toy-spring 項(xiàng)目時(shí),也在項(xiàng)目中簡(jiǎn)單集成了 AspectJ。通過(guò)集成 AspectJ,使得 toy-spring AOP 可以基于 AspectJ 表達(dá)式完成復(fù)雜的匹配邏輯。接下來(lái)就讓我們看看袖珍版 Spring AOP 是怎樣實(shí)現(xiàn)的吧。

    在 toy-spring 中,AOP 和 IOC 產(chǎn)生聯(lián)系的具體實(shí)現(xiàn)類是 AspectJAwareAdvisorAutoProxyCreator(下面簡(jiǎn)稱 AutoProxyCreator),這個(gè)類實(shí)現(xiàn)了 BeanPostProcessor 和 BeanFactoryAware 接口。BeanFactory 在注冊(cè) BeanPostProcessor 接口相關(guān)實(shí)現(xiàn)類的階段,會(huì)將其本身注入到 AutoProxyCreator 中,為后面 AOP 給 bean 生成代理對(duì)象做準(zhǔn)備。BeanFactory 初始化結(jié)束后,AOP 與 IOC 橋梁類 AutoProxyCreator 也完成了實(shí)例化,并被緩存在 BeanFactory 中,靜待 BeanFactory 實(shí)例化 bean。當(dāng)外部產(chǎn)生調(diào)用,BeanFactory 開(kāi)始實(shí)例化 bean 時(shí)。AutoProxyCreator 就開(kāi)始悄悄的工作了,工作細(xì)節(jié)如下:

  • 從 BeanFactory 查找實(shí)現(xiàn)了 PointcutAdvisor 接口的切面對(duì)象,切面對(duì)象中包含了實(shí)現(xiàn) Pointcut 和 Advice 接口的對(duì)象。
  • 使用 Pointcut 中的表達(dá)式對(duì)象匹配當(dāng)前 bean 對(duì)象。如果匹配成功,進(jìn)行下一步。否則終止邏輯,返回 bean。
  • JdkDynamicAopProxy 對(duì)象為匹配到的 bean 生成代理對(duì)象,并將代理對(duì)象返回給 BeanFactory。
  • 經(jīng)過(guò)上面3步,AutoProxyCreator 就悄無(wú)聲息的把原來(lái)的 bean 替換為代理對(duì)象了,是不是有種偷天換日的感覺(jué)。最后把 toy-spring AOP 剩余的實(shí)現(xiàn)代碼貼出來(lái):

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {private XmlBeanFactory xmlBeanFactory;@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {/* 這里兩個(gè) if 判斷很有必要,如果刪除將會(huì)使程序進(jìn)入死循環(huán)狀態(tài),* 最終導(dǎo)致 StackOverflowError 錯(cuò)誤發(fā)生*/if (bean instanceof AspectJExpressionPointcutAdvisor) {return bean;}if (bean instanceof MethodInterceptor) {return bean;}// 1. 從 BeanFactory 查找 AspectJExpressionPointcutAdvisor 類型的對(duì)象List<AspectJExpressionPointcutAdvisor> advisors =xmlBeanFactory.getBeansForType(AspectJExpressionPointcutAdvisor.class);for (AspectJExpressionPointcutAdvisor advisor : advisors) {// 2. 使用 Pointcut 對(duì)象匹配當(dāng)前 bean 對(duì)象if (advisor.getPointcut().getClassFilter().matchers(bean.getClass())) {ProxyFactory advisedSupport = new ProxyFactory();advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces());advisedSupport.setTargetSource(targetSource);// 3. 生成代理對(duì)象,并返回return advisedSupport.getProxy();}}// 2. 匹配失敗,返回 beanreturn bean;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws Exception {xmlBeanFactory = (XmlBeanFactory) beanFactory;} }

    ProxyFactory 實(shí)現(xiàn)代碼:

    1 2 3 4 5 6 7 8 9 10 11 12 13 /*** AopProxy 實(shí)現(xiàn)類的工廠類*/ public class ProxyFactory extends AdvisedSupport implements AopProxy {@Overridepublic Object getProxy() {return createAopProxy().getProxy();}private AopProxy createAopProxy() {return new JdkDynamicAopProxy(this);} }

    測(cè)試類:

    1 2 3 4 5 6 7 8 9 10 public class XmlBeanFactoryTest {@Testpublic void getBean() throws Exception {System.out.println("--------- AOP test ----------");String location = getClass().getClassLoader().getResource("spring.xml").getFile();XmlBeanFactory bf = new XmlBeanFactory(location);HelloService helloService = (HelloService) bf.getBean("helloService");helloService.sayHelloWorld();} }

    測(cè)試結(jié)果:

    ?4. 寫(xiě)在最后

    到此,本文的主要內(nèi)容寫(xiě)完了。如果你耐心的讀完了文章,并感覺(jué)不錯(cuò)的話,歡迎猛點(diǎn)贊和收藏按鈕。這篇文章花了我一天的時(shí)間,寫(xiě)的實(shí)在有點(diǎn)累,也深感認(rèn)真寫(xiě)博客的不易。本篇文章與?仿照 Spring 實(shí)現(xiàn)簡(jiǎn)單的 IOC 和 AOP - 上篇,Spring bean的生命流程?共三篇文章,對(duì) Spring IOC 和 AOP 的實(shí)現(xiàn)原理進(jìn)行了較為詳細(xì)的結(jié)束。也是通過(guò)認(rèn)真編寫(xiě)這三篇文章,使得我對(duì) Spring 框架原理有了更進(jìn)一步的認(rèn)識(shí)。當(dāng)然限于我的經(jīng)驗(yàn)和能力,以上三篇文章中可能存在著一些錯(cuò)誤。如果這些錯(cuò)誤給大家造成了干擾,我表示很抱歉。所以文章若有疏漏不妥之處,還請(qǐng)指出來(lái),如果能不吝賜教,那就更好了。好了,最后感謝大家耐心讀完我的文章,下次再見(jiàn)。

    ?參考:

    • 《Spring揭秘》

    • tiny-spring

    ?附錄:Spring 源碼分析文章列表

    ?Ⅰ. IOC

    更新時(shí)間標(biāo)題
    2018-05-30Spring IOC 容器源碼分析系列文章導(dǎo)讀
    2018-06-01Spring IOC 容器源碼分析 - 獲取單例 bean
    2018-06-04Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過(guò)程
    2018-06-06Spring IOC 容器源碼分析 - 創(chuàng)建原始 bean 對(duì)象
    2018-06-08Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法
    2018-06-11Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對(duì)象
    2018-06-11Spring IOC 容器源碼分析 - 余下的初始化工作

    ?Ⅱ. AOP

    更新時(shí)間標(biāo)題
    2018-06-17Spring AOP 源碼分析系列文章導(dǎo)讀
    2018-06-20Spring AOP 源碼分析 - 篩選合適的通知器
    2018-06-20Spring AOP 源碼分析 - 創(chuàng)建代理對(duì)象
    2018-06-22Spring AOP 源碼分析 - 攔截器鏈的執(zhí)行過(guò)程

    ?Ⅲ. MVC

    更新時(shí)間標(biāo)題
    2018-06-29Spring MVC 原理探秘 - 一個(gè)請(qǐng)求的旅行過(guò)程
    2018-06-30Spring MVC 原理探秘 - 容器的創(chuàng)建過(guò)程
    • 本文鏈接:?https://www.tianxiaobo.com/2018/01/18/自己動(dòng)手實(shí)現(xiàn)的-Spring-IOC-和-AOP-下篇/

    from:http://www.tianxiaobo.com/2018/01/18/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E5%AE%9E%E7%8E%B0%E7%9A%84-Spring-IOC-%E5%92%8C-AOP-%E4%B8%8B%E7%AF%87/?

    總結(jié)

    以上是生活随笔為你收集整理的自己动手实现的 Spring IOC 和 AOP - 下篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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