国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

仿照 Spring 實(shí)現(xiàn)簡(jiǎn)單的 IOC 和 AOP - 下篇

AlexTuan / 1995人閱讀

摘要:在上文中,我實(shí)現(xiàn)了一個(gè)很簡(jiǎn)單的和容器。比如,我們所熟悉的就是在這里將切面邏輯織入相關(guān)中的。初始化的工作算是結(jié)束了,此時(shí)處于就緒狀態(tài),等待外部程序的調(diào)用。其中動(dòng)態(tài)代理只能代理實(shí)現(xiàn)了接口的對(duì)象,而動(dòng)態(tài)代理則無(wú)此限制。

1. 背景

本文承接上文,來(lái)繼續(xù)說(shuō)說(shuō) IOC 和 AOP 的仿寫。在上文中,我實(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ì)的描述。如果大家有興趣,我還是很建議大家跟著寫一遍,因?yàn)楹芏鄷r(shí)候能看懂,但是寫的卻不一定能寫出來(lái)。仿寫一遍能夠加深對(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 版本編寫的。部分類的設(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 被銷毀

上面簡(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)硬盤等。透過(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),看下面的代碼:

public class PropertyValues {

    private final List propertyValueList = new ArrayList();

    public void addPropertyValue(PropertyValue pv) {
        // 在這里可以對(duì)參數(shù)值 pv 做一些處理,如果直接使用 List,則就不行了
        this.propertyValueList.add(pv);
    }

    public List 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ì)象中

鍵值對(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ì)將它解析得到的 鍵值對(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à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ì)象生成器的邏輯主要寫在了 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)代碼:

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ì)象
     */
    @Override
    public 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
     */
    @Override
    public 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 的父接口繼承了 Advice
            MethodInterceptor 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 的原始方法 method
            return 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è)試類:

public class LogInterceptor implements MethodInterceptor {

    @Override
    public 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 {

    @Test
    public void getProxy() throws Exception {
        System.out.println("---------- no proxy ----------");
        HelloService helloService = new HelloServiceImpl();
        helloService.sayHelloWorld();

        System.out.println("
----------- 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)切面功能。所以我在編寫 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):

public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {

    private XmlBeanFactory xmlBeanFactory;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
        return bean;
    }

    @Override
    public 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 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. 匹配失敗,返回 bean
        return bean;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws Exception {
        xmlBeanFactory = (XmlBeanFactory) beanFactory;
    }
}

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

/**
 * AopProxy 實(shí)現(xiàn)類的工廠類
 */
public class ProxyFactory extends AdvisedSupport implements AopProxy {
    @Override
    public Object getProxy() {
        return createAopProxy().getProxy();
    }

    private AopProxy createAopProxy() {
        return new JdkDynamicAopProxy(this);
    }
}

測(cè)試類:

public class XmlBeanFactoryTest {
    @Test
    public 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. 寫在最后

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

參考:

《Spring揭秘》

??tiny-spring

本文在知識(shí)共享許可協(xié)議 4.0 下發(fā)布,轉(zhuǎn)載請(qǐng)注明出處
作者:coolblog
為了獲得更好的分類閱讀體驗(yàn),
請(qǐng)移步至本人的個(gè)人博客:http://www.coolblog.xyz


本作品采用知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議進(jìn)行許可。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70191.html

相關(guān)文章

  • 仿照 Spring 實(shí)現(xiàn)簡(jiǎn)單 IOC AOP - 上篇

    摘要:不過(guò)那個(gè)實(shí)現(xiàn)太過(guò)于簡(jiǎn)單,和,相去甚遠(yuǎn)。在接下來(lái)文章中,我也將從易到難,實(shí)現(xiàn)不同版本的和。切面切面包含了通知和切點(diǎn),通知和切點(diǎn)共同定義了切面是什么,在何時(shí),何處執(zhí)行切面邏輯。 1. 背景 我在大四實(shí)習(xí)的時(shí)候開(kāi)始接觸 J2EE 方面的開(kāi)發(fā)工作,也是在同時(shí)期接觸并學(xué)習(xí) Spring 框架,到現(xiàn)在也有快有兩年的時(shí)間了。不過(guò)之前沒(méi)有仿寫過(guò) Spring IOC 和 AOP,只是宏觀上對(duì) Spri...

    layman 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析系列文章導(dǎo)讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過(guò)這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來(lái)了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開(kāi)發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過(guò)十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...

    NSFish 評(píng)論0 收藏0
  • 【好好面試】你必須要懂Spring-Aop

    摘要:干貨點(diǎn)此處是好好面試系列文的第篇文章。而這也是出現(xiàn)的原因,沒(méi)錯(cuò),就是被設(shè)計(jì)出來(lái)彌補(bǔ)短板的。運(yùn)行結(jié)果如下運(yùn)行結(jié)果可想而知,的通過(guò)驗(yàn)證,的失敗。 【干貨點(diǎn)】此處是【好好面試】系列文的第10篇文章。看完該篇文章,你就可以了解Spring中Aop的相關(guān)使用和原理,并且能夠輕松解答Aop相關(guān)的面試問(wèn)題。 在實(shí)際研發(fā)中,Spring是我們經(jīng)常會(huì)使用的框架,畢竟它們太火了,也因此Spring相關(guān)的知...

    honhon 評(píng)論0 收藏0
  • Spring Boot [配置-下篇]

    摘要:進(jìn)行異常的捕捉與錯(cuò)誤信息頁(yè)面的定制。告訴,這是一個(gè)對(duì)象,該對(duì)象應(yīng)該被注冊(cè)為在應(yīng)用程序上下文中的。不同框架的不同配置這里以作為演示默認(rèn)情況下,保護(hù)已啟用。你必須配置包含令牌的所有的網(wǎng)頁(yè)來(lái)工作。該命名結(jié)構(gòu)旨在幫你找到需要的。 導(dǎo)讀: 在上篇文章中我們了解到Spring Boot 的一些常用的外部化配置,在本篇中我們將會(huì)繼續(xù)對(duì)類的配置進(jìn)行了解 一個(gè)簡(jiǎn)單的例子[錯(cuò)誤頁(yè)面定制]: 在 Spr...

    StonePanda 評(píng)論0 收藏0
  • Spring框架學(xué)習(xí)筆記(一):官方文檔介紹,IoCAOP概念學(xué)習(xí)

    摘要:構(gòu)造函數(shù)注入通過(guò)調(diào)用類的構(gòu)造函數(shù),將接口實(shí)現(xiàn)類通過(guò)構(gòu)造函數(shù)變量傳入。而在中,其使用橫切技術(shù),將這類代碼從原屬的封裝對(duì)象中提取出來(lái),封裝到一個(gè)可重用模塊中,稱為。 最近實(shí)習(xí)用到Spring的開(kāi)發(fā)框架,但是之前沒(méi)有接觸過(guò),因此希望利用網(wǎng)上的資源來(lái)學(xué)習(xí)以下。 Spring官方給出了非常全面的介紹,非常適合我這種完全的小白……在這一系列學(xué)習(xí)中,我閱讀的主要資源是5.1.2 Reference ...

    mindwind 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<