java設計模式之代理模式


java代理模式是一種常見的設計模式。

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

二、常見的代理模式有哪些?

  1. 遠程代理:為不同地理的對象,提供局域網代表對象。
  2. 虛擬代理:根據需要將資源消耗很大的對象進行延遲,真正需要的時候進行創建。
  3. 保護代理:控制對一個對象訪問的權限。
  4. 智能引用代理:提供對目標對象額外的服務。

三、代理模式的兩種實現方式

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

四、示例

1.通過繼承實現靜態代理

首先,先寫一個接口

public interface Moveable {
    
    void move();
    
}

然后寫接口的實現類

public class Car implements Moveable {

    @Override
    public void move() {    
        //實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
        } 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("汽車結束行駛......"); System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!"); } }

測試方法

public class Test{
    public static void main(String[] args) {
        //使用繼承方式實現
        Moveable m = new Car2();
        m.move();
    }
}

2.通過聚合實現靜態代理

編寫聚合類(通過將參數傳遞進來,然后我們使用傳遞進來的參數,調用其方法,實現靜態代理)

public class Car3 implements Moveable{

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

    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("汽車開始行駛.......");
     //通過構造方法將car傳進來,然后通過car調用方法 car.move();
long endtime = System.currentTimeMillis(); System.out.println("汽車結束行駛......"); System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!"); } }

測試方法

public class Test {
    public static void main(String[] args) {
        //使用聚合方式實現
        Car car = new Car();
        Moveable m = new Car3(car);
        m.move();
        }
}    

使用繼承實現靜態代理,會讓我們的代理類無限制的膨脹下去,所以推薦使用聚合實現靜態代理。

五、JDK動態代理

1.定義

在代理類和被代理類之間加上一個事務處理器,將我們需要處理的具體功能放在其中進行處理。

InvocationHandler接口(事務處理器)中僅定義了一個方法public object invoke(Object obj,Method method,Object[] args),在實際使用中,第一個參數obj一般是指代理類,method是被代理的方法,args為該方法的參數數組,這個抽象方法在代理類中動態實現。

Proxy:該類即為動態代理類,通過newProxyInstance方法可以返回代理類的一個實例,返回后的代理類可以當做被代理類使用(可使用被代理類的在接口中聲明過的方法)。

2.實現步驟

  1. 創建一個實現接口InvocationHandler的類,它必須實現invoke方法,在invoke方法中添加具體的業務邏輯。
  2. 創建被代理的類和接口。
  3. 調用Proxy的靜態方法newProxyInstance,動態創建一個代理類。
  4. 通過代理調用方法。

3.示例

public class TimeHandler implements InvocationHandler{    
    private Object target;
    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    @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("汽車結束行駛......");
        System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!");        
        return null;
    }
}
public class TestProxy {
    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();
    }
}

六、CGLIB動態代理

 示例:

首先需引入cglib的jar包

對應的實體類

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 Test {
    public static void main(String[] args) {
        //創建返回代理類對象
        CglibProxy proxy = new CglibProxy();
        //為trian返回代理類對象
        Train t = (Train) proxy.getProxy(Train.class);
        //調用方法
        t.move();
    }
}

JDK動態代理和CGLIB動態代理的區別

JDK動態代理:

  1. 只能代理實現了接口的類。
  2. 沒有實現接口的類不能實現JDK的動態代理。

CGLIB動態代理:

  1. 針對類來實現代理。
  2. 對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的調用。

動態代理的典型應用:spring AOP:同時用到了JDK動態代理和CGLIB動態代理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM