設計模式-代理模式

代理模式的定義:因爲某些緣由須要給某對象提供一個代理以控制對該對象的訪問。這時,訪問對象不適合或者不能直接引用目標對象,代理對象做爲訪問對象和目標對象之間的中介。java

代理模式的主要優勢有:
代理模式在客戶端與目標對象之間起到一箇中介做用和保護目標對象的做用;
代理對象能夠擴展目標對象的功能;
代理模式能將客戶端與目標對象分離,在必定程度上下降了系統的耦合度;spring

其主要缺點是:
在客戶端和目標對象之間增長一個代理對象,會形成請求處理速度變慢;
增長了系統的複雜度;sql

模式結構

代理模式的主要角色以下。
抽象主題(Subject)類:經過接口或抽象類聲明真實主題和代理對象實現的業務方法。
真實主題(Real Subject)類:實現了抽象主題中的具體業務,是代理對象所表明的真實對象,是最終要引用的對象。
代理(Proxy)類:提供了與真實主題相同的接口,其內部含有對真實主題的引用,它能夠訪問、控制或擴展真實主題的功能。shell

源碼導讀

在代理模式中動態代理是在各個框架中使用最普遍的一種設計模式,dubbo中 feign中 mybaits中,都有使用到動態代理。在dubbo中,在接口上添加@refrence ,dubbo就會根據這個接口生成一個代理實例來供消費者用生產者。在feign中也是同樣;mybatis中你只要指定包掃描的路徑,就會在spring中注入一個mapper,實際上這個mapper就是根據接口和xml生成的代理對象。實際上,這種「申明式的」功能實現方式,都是經過代理模式來實現的。設計模式

下面咱們經過cglib來寫一個「殘疾縮水」版的mybatis:安全

首先要整一個xml,我這裏用properties代替服務器

test.properties:mybatis

testA=select * from user where id=
testB=select * from user where username=

再整一個接口:app

interface Test {

    String testA(int id);
    String testB(String username);
}

再是代碼加強處理器,這裏面完成對接口的代理邏輯框架

class MyInvokationHandler implements MethodInterceptor {

    private static Map<String,String> sqlMap;

    {
        HashMap<String, String> map = new HashMap<>();



        Properties prop = new Properties();
        InputStream in = SystemMenuController.class.getClassLoader().getResourceAsStream("test.properties");
        try {
            prop.load(in);
            Iterator<String> it = prop.stringPropertyNames().iterator();
            while (it.hasNext()) {
                String key = it.next();
                map.put(key,prop.getProperty(key));
            }
            in.close();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
        sqlMap=map;
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String name = method.getName();
        String s = sqlMap.get(name);
        return s+objects[0];
    }
}

包掃描和啓動時注入容器略,數據源也略,用個main方法模擬一下:

public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Test.class);
        enhancer.setCallback(new MyInvokationHandler());
        Test test = (Test) enhancer.create();
        System.out.println(test.testA(1));
         System.out.println(test.testB("hhh"));
    }

最終在控制檯中打印:

select * from user where id=1
select * from user where id=hhh

代理模式是一個很強大實用性很強的模式,動態代理大大減小了咱們的開發任務,同時減小了對業務接口的依賴,下降了耦合度。代理模式的使用場景能夠總結爲:

  • 遠程代理,這種方式一般是爲了隱藏目標對象存在於不一樣地址空間的事實,方便客戶端訪問。例如,用戶申請某些網盤空間時,會在用戶的文件系統中創建一個虛擬的硬盤,用戶訪問虛擬硬盤時實際訪問的是網盤空間。
  • 虛擬代理,這種方式一般用於要建立的目標對象開銷很大時。例如,下載一幅很大的圖像須要很長時間,因某種計算比較複雜而短期沒法完成,這時能夠先用小比例的虛擬代理替換真實的對象,消除用戶對服務器慢的感受。
  • 安全代理,這種方式一般用於控制不一樣種類客戶對真實對象的訪問權限。
  • 智能指引,主要用於調用目標對象時,代理附加一些額外的處理功能。例如,增長計算真實對象的引用次數的功能,這樣當該對象沒有被引用時,就能夠自動釋放它。
  • 延遲加載,指爲了提升系統的性能,延遲對目標的加載。例如,Hibernate 中就存在屬性的延遲加載和關聯表的延時加載。

點擊關注個人博客

相關文章
相關標籤/搜索