1. 程式人生 > >如何解決代理模式詳解的原理詳解

如何解決代理模式詳解的原理詳解

 我特意將本系列改了下名字,原名是《設計模式學習之路》,原因是因為之前寫過一篇《spring原始碼學習之路》,但是我感覺本次寫二十三種設計模式,更多的還是分享給各位自己的理解,所以感覺學習之路有點不合適,另外,從本章開始,正式啟用本人稱呼,LZ。

               好了,廢話至此,本章接著討論第二種要介紹的設計模式,代理模式。

               LZ不希望寫的東西與網路上的資料千篇一律,所以這一系列不會像很多典型文章一章,只是列出這個模式的定義以及一堆適用的情況,然後就是一堆這個模式的各個角色,對於這種羅列LZ並不反對,相比之下會比較清晰,但是如果脫離了實際,就會導致看的人特別是初學者覺得設計模式很陌生很遙遠。

               LZ並不反對這種教學式的標準模式,但說實話,LZ本人看這種帖子從來都感覺收穫不大,看一遍看一遍,到現在都沒記住那些各個適用的情況與一堆亂七八糟的角色。

               所以LZ探討代理模式,不會再按這個步驟進行,而是跟著自己的思維進行。

               首先代理模式,可以分為兩種,一種是靜態代理,一種是動態代理。

               兩種代理從虛擬機器載入類的角度來講,本質上都是一樣的,都是在原有類的行為基礎上,加入一些多出的行為,甚至完全替換原有的行為。

               靜態代理採用的方式就是我們手動的將這些行為換進去,然後讓編譯器幫我們編譯,同時也就將位元組碼在原有類的基礎上加入一些其他的東西或者替換原有的東西,產生一個新的與原有類介面相同卻行為不同的型別。

               說歸說,我們來真實的去試驗一下,實驗的話需要找一個示例,就拿我們的資料庫連線來做例子吧。

               我們都知道,資料庫連線是很珍貴的資源,頻繁的開關資料庫連線是非常浪費伺服器的CPU資源以及記憶體的,所以我們一般都是使用資料庫連線池來解決這一問題,即創造一堆等待被使用的連線,等到用的時候就從池裡取一個,不用了再放回去,資料庫連線在整個應用啟動期間,幾乎是不關閉的,除非是超過了最大閒置時間。

               但是在程式設計師編寫程式的時候,會經常使用connection.close()這樣的方法,去關閉資料庫連線,而且這樣做是對的,所以你並不能告訴程式設計師們說,你們使用連線都不要關了,去呼叫一個其他的類似歸還給連線池的方法吧。這是不符合程式設計師的程式設計思維的,也很勉強,而且具有風險性,因為程式設計師會忘的。

               解決這一問題的辦法就是使用代理模式,因為代理模式可以替代原有類的行為,所以我們要做的就是替換掉connection的close行為。

               下面是connection介面原有的樣子,我去掉了很多方法,因為都類似,全貼上來佔地方。

  1. import java.sql.SQLException;  
  2. import java.sql.Statement;  
  3. import java.sql.Wrapper;  
  4. publicinterface Connection  extends Wrapper {  
  5.     Statement createStatement() throws SQLException;  
  6.     void close() throws SQLException;  
  7. }  
              這裡只貼了兩個方法,但是我們代理的精髓只要兩個方法就能掌握,下面使用靜態代理,採用靜態代理我們通常會使用組合的方式,為了保持對程式猿是透明的,我們實現Connection這個介面。

              如下所示。

  1. import java.sql.SQLException;  
  2. import java.sql.Statement;  
  3. publicclass ConnectionProxy implements Connection{  
  4.     private Connection connection;  
  5.     public ConnectionProxy(Connection connection) {  
  6.         super();  
  7.         this.connection = connection;  
  8.     }  
  9.     public Statement createStatement() throws SQLException{  
  10.         return connection.createStatement();  
  11.     }  
  12.     publicvoid close() throws SQLException{  
  13.         System.out.println("不真正關閉連線,歸還給連線池");  
  14.     }  
  15. }  
                我們在構造方法中讓呼叫者強行傳入一個原有的連線,接下來我們將我們不關心的方法,交給真正的Connection介面去處理,就像createStatement方法一樣,而我們將真正關心的close方法用我們自己希望的方式去進行。

                此處為了更形象,LZ給出一個本人寫的非常簡單的連線池,意圖在於表明實現的思路。下面我們來看一下連線池的變化,在裡面註明了變化點。

  1. import java.sql.Connection;  
  2. import java.sql.DriverManager;  
  3. import java.sql.SQLException;  
  4. import java.util.LinkedList;  
  5. publicclass DataSource {  
  6.     privatestatic LinkedList<Connection> connectionList = new LinkedList<Connection>();  
  7.     static{  
  8.         try {  
  9.             Class.forName("com.mysql.jdbc.Driver");  
  10.         } catch (ClassNotFoundException e) {  
  11.             e.printStackTrace();  
  12.         }  
  13.     }  
  14.     privatestatic Connection createNewConnection() throws SQLException{  
  15.         return DriverManager.getConnection("url","username""password");  
  16.     }  
  17.     private DataSource(){  
  18.         if (connectionList == null || connectionList.size() == 0) {  
  19.             for (int i = 0; i < 10; i++) {  
  20.                 try {  
  21.                     connectionList.add(createNewConnection());  
  22.                 } catch (SQLException e) {  
  23.                     e.printStackTrace();  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28.     public Connection getConnection() throws Exception{  
  29.         if (connectionList.size() > 0) {  
  30.             //return connectionList.remove();  這是原有的方式,直接返回連線,這樣可能會被程式設計師把連線給關閉掉
  31.             //下面是使用代理的方式,程式設計師再呼叫close時,就會歸還到連線池
  32.             returnnew ConnectionProxy(connectionList.remove());  
  33.         }  
  34.         returnnull;  
  35.     }  
  36.     publicvoid recoveryConnection(Connection connection){  
  37.         connectionList.add(connection);  
  38.     }  
  39.     publicstatic DataSource getInstance(){  
  40.         return DataSourceInstance.dataSource;  
  41.     }  
  42.     privatestaticclass DataSourceInstance{  
  43.         privatestatic DataSource dataSource = new DataSource();  
  44.     }  
  45. }  
                連線池我們把它做成單例,所以假設是上述連線池的話,我們代理中的close方法可以再具體化一點,就像下面這樣,用歸還給連線池的動作取代關閉連線的動作。
  1. publicvoid close() throws SQLException{  
  2.     DataSource.getInstance().recoveryConnection(connection);  
  3. }  

                好了,這下我們的連線池返回的連線全是代理,就算程式設計師呼叫了close方法也只會歸還給連線池了。

                我們使用代理模式解決了上述問題,從靜態代理的使用上來看,我們一般是這麼做的。

                1,代理類一般要持有一個被代理的物件的引用。

                2,對於我們不關心的方法,全部委託給被代理的物件處理。

                3,自己處理我們關心的方法。

                這種代理是死的,不會在執行時動態建立,因為我們相當於在編譯期,也就是你按下CTRL+S的那一刻,就給被代理的物件生成了一個不可動態改變的代理類。

               靜態代理對於這種,被代理的物件很固定,我們只需要去代理一個類或者若干固定的類,數量不是太多的時候,可以使用,而且其實效果比動態代理更好,因為動態代理就是在執行期間動態生成代理類,所以需要消耗的時間會更久一點。就像上述的情況,其實就比較適合使用靜態代理。

               下面介紹下動態代理,動態代理是JDK自帶的功能,它需要你去實現一個InvocationHandler介面,並且呼叫Proxy的靜態方法去產生代理類。

               接下來我們依然使用上面的示例,但是這次該用動態代理處理,我們來試一下看如何做。

  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3. import java.lang.reflect.Proxy;  
  4. import java.sql.Connection;  
  5. publicclass ConnectionProxy implements InvocationHandler{  
  6.     private Connection connection;  
  7.     public ConnectionProxy(Connection connection) {  
  8.         super();  
  9.         this.connection = connection;  
  10.     }  
  11.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  12.         //這裡判斷是Connection介面的close方法的話
  13. 相關推薦

    Java代理模式實現與原理(一)

    關於Java中的代理,我們首先需要了解的是一種常用的設計模式——代理模式,而對於代理,可根據代理類建立的時間點,分為靜態代理和動態代理。今天我們先來了解一下Java中的靜態代理。 1 代理模式 代理模式是一種常用的設計模式,百度百科中對其定義為:為其他物件提供一個代理以控制對某個物件的訪問。

    如何解決代理模式原理

     我特意將本系列改了下名字,原名是《設計模式學習之路》,原因是因為之前寫過一篇《spring原始碼學習之路》,但是我感覺本次寫二十三種設計模式,更多的還是分享給各位自己的理解,所以感覺學習之路有點不合適,另外,從本章開始,正式啟用本人稱呼,LZ。        

    動態代理模式(例項化

    簡介 代理模式通常用於達到對原有系統功能進行擴充的目的 比如:你剛接手一個別人沒有完成的專案,這是你不想動別人原理的程式碼,還需要新增新功能。這時代理模式,這時代理模式,這時代理模式會很好的幫助解決問題 代理模式分為兩種: 靜態代理模式 、 動態代理模式 靜態代理 靜態代理一般是

    設計模式代理模式 c++實現以及

    proxy模式 <1> 作用:為其他物件提供一種代理以控制對這個物件的訪問。 <2> 代理模式的應用場景:如果已有的方法在使用的時候需要對原有的方法進行改進,此時有兩種辦法:1、修改原有的方法來適應。這樣違反了“對擴充套件開放,對修改關閉”的原則。2

    設計模式與應用:代理模式(三種

    簡介 Proxy代理模式,是構造型的設計模式之一 代理模式為其他物件提供代理以控制這個物件的訪問。 所謂代理,是指具有與代理元(被代理物件)具有相同介面的類。client需要通過代理與被代理的目標類互動,代理類就是在互動的過程中(前後

    Java設計模式——代理模式實現及原理

    簡介 Java程式設計的目標是實現現實不能完成的,優化現實能夠完成的,是一種虛擬技術。生活中的方方面面都可以虛擬到程式碼中。代理模式所講的就是現實生活中的這麼一個概念:中介。 代理模式的定義:給某一個物件提供一個代理,並由代理物件控制對原物件的引用。 代理模式包含如下角色:

    設計模式之---代理模式(AOP的原理)

    代理模式有三種:靜態代理,動態代理,Cglib代理。 代理模式的功能主要是起到增強方法和許可權攔截的作用。 1.靜態代理: 其實代理模式根據這個名字就很好理解,舉個簡單例子:小明要去租房,但他找不

    解決ajax跨域的方法原理之Cors方法

    詳細 不同 htm 渲染 jsonp del 需要 methods href 1、神馬是跨域(Cross Domain) 對於端口和協議的不同,只能通過後臺來解決。 一句話:同一個ip、同一個網絡協議、同一個端口,三者都滿足就是同一個域,否則就是 跨域問題了。而為

    火熱的足球廣告平臺代理模式

    索引 根據 客戶 存在 自身 實現 搜索 還要 擁有 什麽是足球廣告平臺? 足球廣告平臺是一款連接廣告與受眾的新型平臺。   以往廣告通常需要找到一個擁有大量流量的媒體,一般有報紙、電視臺、微博大v、自媒體大v等。這類流量有個共同點,就是廣告主出相應費用,讓他們一次或者多次

    java代理模式

    之前 OS 另一個 string nds quest blog abs oid java代理模式詳解 1. 代理模式 代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象

    華為交換機私有hybird接口模式:(案例+原理

    華為 hybird 華為交換機私有hybird接口模式:(案例+原理詳解) 實驗說明: 準備:如圖pc1 pc2同屬於VLAN10,配置相應的ippc3 pc4同屬於VLAN20 配置相應的ipClient 屬於 VLAN30 配置pc1同網段ipPc1 pc2 client 屬於同網段

    Java 中的三種代理模式

    繼承 jvm 保存 3.2 指令集 throwable eth args 代理類 代理模式 代理(Proxy)是一種設計模式,提供了對目標對象另外的訪問方式;即通過代理對象訪問目標對象.這樣做的好處是:可以在目標對象實現的基礎上,增強額外的功能操作,即擴展目標

    代理模式(一)---SpringAOP的兩種實現代理模式的詳細解讀

       現在在生活中,許多軟體系統都提供跨網路和系統的應用,但在跨網路和系統應用時,作為系統開發者並不希望客戶直接訪問系統中的物件。其中原因很多考慮到系統安全和效能因素,因素還有很多,也就不再進行一一的列舉了,所以,想到了在客戶端和系統端新增一層中間層----代理層,也是即將要介紹的代理模式。   首先,明確

    Nginx反向代理和配置(正向代理、反向代理、負載均衡原理、Nginx反向代理原理和配置講解)

    nginx概述 nginx是一款自由的、開源的、高效能的HTTP伺服器和反向代理伺服器;同時也是一個IMAP、POP3、SMTP代理伺服器;nginx可以作為一個HTTP伺服器進行網站的釋出處理,另外nginx可以作為反向代理進行負載均衡的實現。 Nginx是一款開原始碼的高效能HT

    Docker Kubernetes Service 網絡服務代理模式

    docker mes 內核 外部 docke 支持 用戶空間 bec 標簽 Docker Kubernetes Service 網絡服務代理模式詳解 Service service是實現kubernetes網絡通信的一個服務 主要功能:負載均衡、網絡規則分布到具體pod

    Docker Kubernetes Service 網路服務代理模式

    Docker Kubernetes  Service 網路服務代理模式詳解 Service service是實現kubernetes網路通訊的一個服務 主要功能:負載均衡、網路規則分佈到具體pod 注:kubernetes deployment服務分配伺服器負載均衡VIP只能NO

    Nginx(正向代理、反向代理、負載均衡原理、ginx反向代理原理和配置講解

    nginx概述 nginx是一款自由的、開源的、高效能的HTTP伺服器和反向代理伺服器;同時也是一個IMAP、POP3、SMTP代理伺服器;nginx可以作為一個HTTP伺服器進行網站的釋出處理,另外nginx可以作為反向代理進行負載均衡的實現。 這裡主要通過三

    動態代理 靜態代理 代理模式(講的很好 淺顯易懂)

    們在Java程式碼中定義的。 通常情況下, 靜態代理中的代理類和委託類會實現同一介面或是派生自相同的父類。 一、概述 1. 什麼是代理 我們大家都知道微商代理,簡單地說就是代替廠家賣商品,廠家“委託”代理為其銷售商品。關於微商代理,首先我們從他們那裡買東

    java動態代理模式

    引言:java框架中很多設計都是基於動態代理模式的,所謂動態代理模式,就是動態的產生目標物件的代理類,並規定一個方法,可以執行目標物件的方法,也可以在目標物件方法的基礎上新增其他必要的方法。這裡,詳細介紹一下java中實現動態代理模式的兩種方式 在java中,

    動態代理模式封裝事務

    代理,大家都知道是什麼意思。百科上面的解釋:以他人的名義,在授權範圍內進行對被代理人直接發生法律效力的法律行為。 說白了就是A想交女朋友,但是自己不敢去表白,然後叫B去幫他送花,而B幫助A送了花,B就是代理。 而代理又分為靜態代理和動態代理,那麼什麼是靜態代理呢? 仍然是上