設計模式之代理模式--慕課網筆記

第1章 代理模式概念介紹
1-1 代理模式概念及分類
  • 面向對象的設計思維
  • 瞭解多態的概念
  • 瞭解反射機制

  • 代理模式基本概念及分類

  • 瞭解代理模式開發中應用場景
  • 掌握代理模式實現方法
  • 理解JDK動態代理實現

代理模式定義:爲其他對象提供一種代理以控制這個對象的訪問。
代理對象起到中介作用,可去掉功能服務或增加額外的服務。

  • 遠程代理
    爲不同地理的對象,提供局域網代表對象
  • 虛擬代理
    根據需要將資源消耗很大的對象進行延時,真正需要的時候進行創建
  • 保護代理
    控制對一個對象的訪問的權限
  • 智能代理
    提供對目標對象額外服務
第2章 常用代理模式原理
2-1 靜態代理概念及實現

智能引用代理

  • 靜態代理
  • 動態代理

靜態代理:代理和被代理對象在代理之前是確定的。他們都實現相同的接口或者繼承相同的抽象類。

public interface Moveable {
    void move();
}
public class Car implements Moveable {

    @Override
    public void move() {
        //實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class Car2 extends Car {

    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        super.move();
        long endtime = System.currentTimeMillis();
        System.out.println("汽車結束行駛....  汽車行駛時間:" 
                + (endtime - starttime) + "毫秒!");
    }


}
public class Car3 implements Moveable {

    public Car3(Car car) {
        super();
        this.car = car;
    }

    private Car car;

    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        car.move();
        long endtime = System.currentTimeMillis();
        System.out.println("汽車結束行駛....  汽車行駛時間:" 
                + (endtime - starttime) + "毫秒!");
    }

}
public class Client {

    /**
     * 測試類
     */
    public static void main(String[] args) {
//      Car car = new Car();
//      car.move();
        //使用集成方式
//      Moveable m = new Car2();
//      m.move();
        //使用聚合方式實現
        Car car = new Car();
        Moveable m = new Car3(car);
        m.move();
    }

}

通過繼承和聚合兩種方式都能實現代理,但究竟哪種更好呢?

2-2 聚合比繼承更適合代理模式

實現功能疊加

  • 方法move()
  • 增加方法運行時間處理
  • 增加權限管理
  • 增加日誌處理
public interface Moveable {
    void move();
}
public class Car implements Moveable {

    @Override
    public void move() {
        //實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class CarLogProxy implements Moveable {

    public CarLogProxy(Moveable m) {
        super();
        this.m = m;
    }

    private Moveable m;

    @Override
    public void move() {
        System.out.println("日誌開始....");
        m.move();
        System.out.println("日誌結束....");
    }

}
public class CarTimeProxy implements Moveable {

    public CarTimeProxy(Moveable m) {
        super();
        this.m = m;
    }

    private Moveable m;

    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        m.move();
        long endtime = System.currentTimeMillis();
        System.out.println("汽車結束行駛....  汽車行駛時間:" 
                + (endtime - starttime) + "毫秒!");
    }

}
public class Client {

    /**
     * 測試類
     */
    public static void main(String[] args) {
        Car car = new Car();
        CarLogProxy clp = new CarLogProxy(car);
        CarTimeProxy ctp = new CarTimeProxy(clp);
        ctp.move();
    }

}
2-3 瞭解 JDK 動態代理

動態產生代理,實現對不同類,不同方法的代理

ProxySubject->Proxy–>ProxyHandler–>RealSubject

Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類

  • Interface InvocationHandler:該接口中僅定義了一個方法public object invoke(
    Object obj,Method method,Object[] args)在實際使用時,第一個參數obj一般是指
    代理類,method是被代理的方法,args爲該方法的參數數組。這個抽象方法在代理中
    動態實現。
  • Proxy:該類即爲動態代理類static Object newProxyInstance(ClassLoader loader,
    Class[] interfaces,InvocationHandler h):返回代理類的一個實例,返回後的代理類
    可以當作被代理類使用(可使用被代理類的在接口中聲明過的方法)
public interface Moveable {
    void move();
}
public class Car implements Moveable {

    @Override
    public void move() {
        //實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public class TimeHandler implements InvocationHandler {

    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    private Object target;

    /*
     * 參數:
     * proxy  被代理對象
     * method  被代理對象的方法
     * args 方法的參數
     * 
     * 返回值:
     * Object  方法的返回值
     * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long starttime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        method.invoke(target);
        long endtime = System.currentTimeMillis();
        System.out.println("汽車結束行駛....  汽車行駛時間:" 
                + (endtime - starttime) + "毫秒!");
        return null;
    }

}
public class Test {

    /**
     * JDK動態代理測試類
     */
    public static void main(String[] args) {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Class<?> cls = car.getClass();
        /**
         * loader  類加載器
         * interfaces  實現接口
         * h InvocationHandler
         */
        Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
                                                cls.getInterfaces(), h);
        m.move();
    }

}

所謂Dynamic Proxy是這樣一種class:
它是在運行時生成的class
該class需要實現一組interface
使用動態代理時,必須實現InvocationHandler接口

動態代理實現步驟

  • 創建一個實現接口InvocationHandler的類,它必須實現invoke方法
  • 創建被代理的類以及接口
  • 調用Proxy的靜態方法,創建一個代理類
    newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
  • 通過代理調用方法
2-4 使用 cglib 動態產生代理
  • JDK動態代理
    • 只能代理實現了接口的類
    • 沒有實現接口的類不能實現JDK的動態代理
  • CGLIB動態代理
    • 針對類來實現代理的
    • 對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的調用
public class Train {

    public void move(){
        System.out.println("火車行駛中...");
    }
}
public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz){
        //設置創建子類的類
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);

        return enhancer.create();
    }

    /**
     * 攔截所有目標類方法的調用
     * obj  目標類的實例
     * m   目標方法的反射對象
     * args  方法的參數
     * proxy代理類的實例
     */
    @Override
    public Object intercept(Object obj, Method m, Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("日誌開始...");
        //代理類調用父類的方法
        proxy.invokeSuper(obj, args);
        System.out.println("日誌結束...");
        return null;
    }

}
public class Client {

    /**
     * @param args
     */
    public static void main(String[] args) {

        CglibProxy proxy = new CglibProxy();
        Train t = (Train)proxy.getProxy(Train.class);
        t.move();
    }

}
第3章 自定義類模擬 JDK 動態代理的實現
3-1 模擬 JDK 動態代理實現思路分析及簡單實現

動態代理實現思路
實現功能:通過Proxy的newProxyInstance返回代理對象

  1. 聲明一段源碼(動態產生代理)
  2. 編譯源碼(JDK Compiler API),產生新的類(代理類)
  3. 將這個類load到內存當中,產生一個新的對象(代理對象)
  4. return 代理對象
3-2 完善動態代理實現
public interface Moveable {
    void move();
}
public class Proxy {

    public static Object newProxyInstance(Class infce) throws Exception{
        String rt = "\r\n";
        String methodStr = "";
        for(Method m : infce.getMethods()){
            methodStr += "  @Override" + rt +
            "   public void " + m.getName() + "() {" + rt +
            "       long starttime = System.currentTimeMillis();" + rt +
            "       System.out.println(\"汽車開始行駛....\");" + rt +
            "       m." + m.getName() + "();" + rt +
            "       long endtime = System.currentTimeMillis();" + rt +
            "       System.out.println(\"汽車結束行駛....  汽車行駛時間:\" " + rt +
            "               + (endtime - starttime) + \"毫秒!\");" + rt +
            "   }" ;
        }

        String str =
        "package com.imooc.proxy;" + rt +
        "public class $Proxy0 implements " + infce.getName() + " {" + rt +
        "   public $Proxy0(" + infce.getName() + " m) {" + rt +
        "       super();" + rt +
        "       this.m = m;" + rt +
        "   }" + rt +
        "   private " + infce.getName() + " m;" + rt +
        methodStr + rt +
        "}" ;
        //產生代理類的java文件
        String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str);

        //編譯
        //拿到編譯器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //文件管理者
        StandardJavaFileManager fileMgr = 
                complier.getStandardFileManager(null, null, null);
        //獲取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        //編譯任務
        CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
        //進行編譯
        t.call();
        fileMgr.close();

        //load 到內存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.imooc.proxy.$Proxy0");

        Constructor ctr = c.getConstructor(infce);
        return ctr.newInstance(new Car());
    }




}
public class Client {

    /**
     * 測試類
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class);
        m.move();
    }

}
3-3 動態代理實現添加 InvocationHandler
public interface Moveable {
    void move();
}
public class Car implements Moveable {

    @Override
    public void move() {
        //實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
public interface InvocationHandler {

    public void invoke(Object o,Method m);
}
public class TimeHandler implements InvocationHandler {

    private Object target;

    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m) {

        try {
            long starttime = System.currentTimeMillis();
            System.out.println("汽車開始行駛....");
            m.invoke(target);
            long endtime = System.currentTimeMillis();
            System.out.println("汽車結束行駛....  汽車行駛時間:"
                            + (endtime - starttime) + "毫秒!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
public class Proxy {

    @SuppressWarnings("unchecked")
    public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
        String rt = "\r\n";
        String methodStr = "";
        for(Method m : infce.getMethods()){
            methodStr += "  @Override" + rt +
            "   public void " + m.getName() + "() {" + rt +
            "  try{" + rt +
            "  Method md = " + infce.getName() + ".class.getMethod(\"" 
                                        + m.getName() + "\");" + rt +
            "  h.invoke(this,md);" +rt+ 
            "  }catch(Exception e){ e.printStackTrace();}" + rt +
            "   }" ;
        }

        String str =
        "package com.imooc.proxy;" + rt +
        "import java.lang.reflect.Method;" + rt +
        "import com.imooc.proxy.InvocationHandler;" +  rt+
        "public class $Proxy0 implements " + infce.getName() + " {" + rt +
        "   public $Proxy0(InvocationHandler h) {" + rt +
        "       this.h = h;" + rt +
        "   }" + rt +
        "  private InvocationHandler h;" + rt+ 
        methodStr + rt +
        "}" ;
        //產生代理類的java文件
        String filename = System.getProperty("user.dir") +"/bin/com/imooc/proxy/$Proxy0.java";
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str);

        //編譯
        //拿到編譯器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //文件管理者
        StandardJavaFileManager fileMgr = 
                complier.getStandardFileManager(null, null, null);
        //獲取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        //編譯任務
        CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
        //進行編譯
        t.call();
        fileMgr.close();

        //load 到內存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.imooc.proxy.$Proxy0");

        Constructor ctr = c.getConstructor(InvocationHandler.class);
        return ctr.newInstance(h);
    }




}
public class Client {

    /**
     * 測試類
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
        m.move();
    }

}
第4章 代理模式總結
4-1 課程總結
  • 代理概念、分類及應用場景
  • 靜態代理(繼承、聚合)
  • JDK動態代理實現日誌處理功能
    • 產生動態代理不僅可以使用jdk動態代理,也可以使用其他的方式,如cglib.
  • 模擬JDK動態代理實現

常見代理模

  • 遠程代理
  • 智能引用代理
  • 虛擬代理
  • 保護代理

智能引用代理

  • 日誌處理
  • 權限管理
  • 事務處理

也叫AOP面向切面編程


《模式的祕密—代理模式》視頻地址

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