1. 程式人生 > >Spring 框架的設計理念與設計模式分析(2)

Spring 框架的設計理念與設計模式分析(2)

下面再看看 Spring 是如何呼叫攔截器的,下面是這個過程的時序圖:


圖 20.Spring 呼叫攔截器
圖 20.Spring 呼叫攔截器 

以上所說的都是 Jdk 動態代理,Spring 還支援一種 CGLIB 類代理,感興趣自己看吧。

Spring 中使用的設計模式也很多,比如工廠模式、單例模式、模版模式等,在《 Webx 框架的系統架構與設計模式》、《 Tomcat 的系統架構與模式設計分析》已經有介紹,這裡就不贅述了。這裡主要介紹代理模式和策略模式。

代理模式

代理模式原理

代理模式就是給某一個物件建立一個代理物件,而由這個代理物件控制對原物件的引用,而建立這個代理物件就是可以在呼叫原物件是可以增加一些額外的操作。下面是代理模式的結構:


圖 21. 代理模式的結構
圖 21. 代理模式的結構 
  • Subject:抽象主題,它是代理物件的真實物件要實現的介面,當然這可以是多個介面組成。
  • ProxySubject:代理類除了實現抽象主題定義的介面外,還必須持有所代理物件的引用
  • RealSubject:被代理的類,是目標物件。

Spring 中如何實現代理模式

Spring Aop 中 Jdk 動態代理就是利用代理模式技術實現的。在 Spring 中除了實現被代理物件的介面外,還會有 org.springframework.aop.SpringProxy 和 org.springframework.aop.framework.Advised 兩個介面。Spring 中使用代理模式的結構圖如下:


圖 22. Spring 中使用代理模式的結構圖
圖 22. Spring 中使用代理模式的結構圖 

$Proxy 就是建立的代理物件,而 Subject 是抽象主題,代理物件是通過 InvocationHandler 來持有對目標物件的引用的。

Spring 中一個真實的代理物件結構如下:


清單 10 代理物件 $Proxy4
            public class $Proxy4 extends java.lang.reflect.Proxy implements
            org.springframework.aop.framework.PrototypeTargetTests$TestBean
            org.springframework.aop.SpringProxy
            org.springframework.aop.framework.Advised
            {
            java.lang.reflect.Method m16;
            java.lang.reflect.Method m9;
            java.lang.reflect.Method m25;
            java.lang.reflect.Method m5;
            java.lang.reflect.Method m2;
            java.lang.reflect.Method m23;
            java.lang.reflect.Method m18;
            java.lang.reflect.Method m26;
            java.lang.reflect.Method m6;
            java.lang.reflect.Method m28;
            java.lang.reflect.Method m14;
            java.lang.reflect.Method m12;
            java.lang.reflect.Method m27;
            java.lang.reflect.Method m11;
            java.lang.reflect.Method m22;
            java.lang.reflect.Method m3;
            java.lang.reflect.Method m8;
            java.lang.reflect.Method m4;
            java.lang.reflect.Method m19;
            java.lang.reflect.Method m7;
            java.lang.reflect.Method m15;
            java.lang.reflect.Method m20;
            java.lang.reflect.Method m10;
            java.lang.reflect.Method m1;
            java.lang.reflect.Method m17;
            java.lang.reflect.Method m21;
            java.lang.reflect.Method m0;
            java.lang.reflect.Method m13;
            java.lang.reflect.Method m24;
            int hashCode();
            int indexOf(org.springframework.aop.Advisor);
            int indexOf(org.aopalliance.aop.Advice);
            boolean equals(java.lang.Object);
            java.lang.String toString();
            void sayhello();
            void doSomething();
            void doSomething2();
            java.lang.Class getProxiedInterfaces();
            java.lang.Class getTargetClass();
            boolean isProxyTargetClass();
            org.springframework.aop.Advisor; getAdvisors();
            void addAdvisor(int, org.springframework.aop.Advisor)
            throws org.springframework.aop.framework.AopConfigException;
            void addAdvisor(org.springframework.aop.Advisor)
            throws org.springframework.aop.framework.AopConfigException;
            void setTargetSource(org.springframework.aop.TargetSource);
            org.springframework.aop.TargetSource getTargetSource();
            void setPreFiltered(boolean);
            boolean isPreFiltered();
            boolean isInterfaceProxied(java.lang.Class);
            boolean removeAdvisor(org.springframework.aop.Advisor);
            void removeAdvisor(int)throws org.springframework.aop.framework.AopConfigException;
            boolean replaceAdvisor(org.springframework.aop.Advisor,
            org.springframework.aop.Advisor)
            throws org.springframework.aop.framework.AopConfigException;
            void addAdvice(org.aopalliance.aop.Advice)
            throws org.springframework.aop.framework.AopConfigException;
            void addAdvice(int, org.aopalliance.aop.Advice)
            throws org.springframework.aop.framework.AopConfigException;
            boolean removeAdvice(org.aopalliance.aop.Advice);
            java.lang.String toProxyConfigString();
            boolean isFrozen();
            void setExposeProxy(boolean);
            boolean isExposeProxy();
            }
            

策略模式

策略模式原理

策略模式顧名思義就是做某事的策略,這在程式設計上通常是指完成某個操作可能有多種方法,這些方法各有千秋,可能有不同的適應的場合,然而這些操作方法都有可能用到。各一個操作方法都當作一個實現策略,使用者可能根據需要選擇合適的策略。

下面是策略模式的結構:


圖 23. 策略模式的結構
圖 23. 策略模式的結構 
  • Context:使用不同策略的環境,它可以根據自身的條件選擇不同的策略實現類來完成所要的操作。它持有一個策略例項的引用。建立具體策略物件的方法也可以由他完成。
  • Strategy:抽象策略,定義每個策略都要實現的策略方法
  • ConcreteStrategy:具體策略實現類,實現抽象策略中定義的策略方法

Spring 中策略模式的實現

Spring 中策略模式使用有多個地方,如 Bean 定義物件的建立以及代理物件的建立等。這裡主要看一下代理物件建立的策略模式的實現。

前面已經瞭解 Spring 的代理方式有兩個 Jdk 動態代理和 CGLIB 代理。這兩個代理方式的使用正是使用了策略模式。它的結構圖如下所示:


圖 24. Spring 中策略模式結構圖
圖 24. Spring 中策略模式結構圖 

在上面結構圖中與標準的策略模式結構稍微有點不同,這裡抽象策略是 AopProxy 介面,Cglib2AopProxy 和 JdkDynamicAopProxy 分別代表兩種策略的實現方式,ProxyFactoryBean 就是代表 Context 角色,它根據條件選擇使用 Jdk 代理方式還是 CGLIB 方式,而另外三個類主要是來負責建立具體策略物件,ProxyFactoryBean 是通過依賴的方法來關聯具體策略物件的,它是通過呼叫策略物件的 getProxy(ClassLoader classLoader) 方法來完成操作。

總結

本文通過從 Spring 的幾個核心元件入手,試圖找出構建 Spring 框架的骨骼架構,進而分析 Spring 在設計的一些設計理念,是否從中找出一些好的設計思想,對我們以後程式設計能提供一些思路。接著再詳細分析了 Spring 中是如何實現這些理念的,以及在設計模式上是如何使用的。

通過分析 Spring 給我一個很大的啟示就是其這套設計理念其實對我們有很強的借鑑意義,它通過抽象複雜多變的物件,進一步做規範,然後根據它定義的這套規範設計出一個容器,容器中構建它們的複雜關係,其實現在有很多情況都可以用這種類似的處理方法。

雖然我很想把我對 Spring 的想法完全闡述清楚,但是所謂“書不盡言,言不盡意。”,有什麼不對或者不清楚的地方大家還是看看其原始碼吧。