025-設計模式之動態代理

上篇文章中,Filter過濾器中的案例,對請求過來的參數進行敏感詞彙過濾,如果是敏感詞彙就修改成 *** , 然後再放行給對應的Servlet進行處理請求。那麼通過Filter進行了過濾和增強。加入服務端有100個接口,那麼通過一個Filter就可以對所有的接口請求進行過濾和處理,然後再放行給對應的Servlet。示例裏用到了動態代理,下面簡單介紹下。

 

設計模式:一些通用的解決固定問題的方式 ,這裏介紹 代理模式

概念:

  • 真實對象:被代理的對象
  • 代理對象:
  • 代理模式:代理對象代理真實對象,達到增強真實對象功能的目的

實現方式:

  • 靜態代理:有一個類文件描述代理模式
  • 動態代理:在內存中形成代理類

實現步驟:

  • 代理對象和真實對象實現相同的接口
  • 代理對象 = Proxy.newProxyInstance();
  • 使用代理對象調用方法。
  • 增強方法

增強方式:

  • 增強參數列表
  • 增強返回值類型
  • 增強方法體執行邏輯    

示例

 

定義一個賣電腦的接口

public interface SaleComputer {
    public String sale(double money);
    public void show();
}

定義真實賣電腦的廠商

/**
 * 真實類
 */
public class Lenovo implements SaleComputer {
    @Override
    public String sale(double money) {
        return "花了"+money+"元買了一臺聯想電腦...";
    

    @Override
    public void show() {
        System.out.println("展示電腦....");
    }
}

代理測試

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        //1.創建真實對象
        Lenovo lenovo = new Lenovo();
        //2.動態代理增強lenovo對象
        /*
            三個參數:
                1. 類加載器:真實對象.getClass().getClassLoader()
                2. 接口數組:真實對象.getClass().getInterfaces()
                3. 處理器:new InvocationHandler()
         */
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            /*
                代理邏輯編寫的方法:代理對象調用的所有方法都會觸發該方法執行
                    參數:
                        1. proxy:代理對象
                        2. method:代理對象調用的方法,被封裝爲的對象
                        3. args:代理對象調用的方法時,傳遞的實際參數
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //判斷是否是sale方法
                if(method.getName().equals("sale")){
                    //1.增強參數
                    double money = (double) args[0];
                    money = money * 0.85;
                    System.out.println("專車接你....");
                    //使用真實對象調用該方法
                    String obj = (String) method.invoke(lenovo, money);
                    System.out.println("免費送貨...");
                    //2.增強返回值
                    return obj+"送鼠標墊";
                }else{
                    Object obj = method.invoke(lenovo, args);
                    return obj;
                }
            }
        });

        //3.如果調用代理過的方法
        String computer = proxy_lenovo.sale(1000);
        System.out.println(computer);
        proxy_lenovo.show();

        //如果調用正常的方法
        System.out.println("------");
        lenovo.sale(1000);
        lenovo.show();
    }
}

輸出結果:
專車接你
免費送貨
花了850元買了一臺聯想電腦...送鼠標墊
展示電腦
------
花了1000元買了一臺聯想電腦...
展示電腦

示例中,通過代理,對lenovo 對象的sale方法進行了"增強";

通過Proxy.newProxyInstance 方法生成了一個動態代理的對象,這個對象沒有物理代碼,而是被動態生成在內存中, 

當通過返回的proxy_lenovo代理對象執行方法時, InvocationHandler 的invoke方法會被執行,可以獲取到當前被執行的方法是什麼,參數是什麼,然後你可以動態做一些邏輯處理, 比如這裏就通過代理,對sale方法進行數據處理和加了一些邏輯,然後最後相當於修改了返回值,invoke方法的返回值就是sale方法最後的返回值。

通過示例可以看出,對象被代理後,可以自定義對象方法被調用時的參數,邏輯,返回值,也就是對方法進行"增強".

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章