代理模式淺談

代理模式

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

對象消耗太多資源,並不是每一條邏輯路徑都需要這個對象,延遲創建對象的想法
限制訪問某個對象,提供一組方法給普通用戶,特殊方法給管理員用戶

遠程代理

Remote Proxy
爲不同地理的對象,提供局域網代表對象
遠程代理又稱之爲大師(Ambassador)

遠程代理

虛擬代理

virtual Proxy
根據需要將資源消耗很大的對象進行延遲真正需要的時候進行創建

保護代理

權限控制

智能引用代理

提供額外的服務
取代簡單的指針,它在訪問對象時執行一些附加操作

Copy-on-Write代理

虛擬代理的一種,把複製(克隆)操作延遲到只有客戶端真正需要時才執行

兩種實現方式

  1. 靜態代理
  2. 動態代理

靜態代理

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

汽車行駛

package proxyDemo;

public interface Moveable {
    void move();
}


package proxyDemo;

import java.util.Random;

public class Car implements Moveable {

    @Override
    public void move() {
        long startTime = System.currentTimeMillis();
        System.out.println("汽車開始行駛");
        try {
            System.out.println("汽車行駛中");
            Thread.sleep(new Random().nextInt(1000)); //隨即產生一個大於0小於1000的整數;用進程的例子模擬汽車行駛

        } catch (InterruptedException e) {      
            e.printStackTrace();
        }

        long endTime = System.currentTimeMillis();
        System.out.println("汽車結束行駛");
        System.out.println("汽車行駛時間:"+(endTime-startTime)+"ms");
    }

}

使用代理方式

import java.util.Random;

public class Car implements Moveable {

    @Override
    public void move() {

        try {
            System.out.println("汽車行駛中");
            Thread.sleep(new Random().nextInt(10000));

        } catch (InterruptedException e) {      
            e.printStackTrace();
        }

    }

}

package proxyDemo;

public class proxyCar 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)+"ms");
    }

}

二者的測試類

package proxyDemo;

public class Test {

    public static void main(String[] args) {
//      Car benz = new Car();
//      benz.move();

        Moveable m = new proxyCar();
        m.move();

    }

}

代理簡單結構示意圖

代理UML

  1. 抽象對象 聲明瞭目標對象和代理對象的共同接口
  2. 目標對象 定義了代理對象所代表的目標對象
  3. 代理對象 內部含有目標對象的引用,從而在任何時候操縱目標對象,代理對象提供了與目標對象相同的接口,在任何時候可以替代目標對象.

JDK動態代理

jdk動態代理

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

1.Interface InvocationHandler

public object invoke(Object obj,Method method,Object[] args)

這個抽象方法在代理類中動態實現

2.Proxy

static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)

返回代理類的一個實例,返回後的代理類可以當作被代理類使用

代碼如下

package jdkproxy;

public interface Moveable {
    void move();
}


package jdkproxy;

public class Car implements Moveable{
    public void move()
    {
        System.out.println("---汽車行駛中---");
    }

}

package jdkproxy;

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

public class TimeHandler implements InvocationHandler {

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

private Object target;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // TODO Auto-generated method stub

    System.out.println("---時間處理---");

    method.invoke(target);

    System.out.println("---時間結束---");
    return null;
}

}

package jdkproxy;

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



//JDK動態代理測試類

public class Test {

    public static void main(String[] args) {

        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Class<?> cls = car.getClass();

        Moveable m =(Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),h);
        m.move();

    }

}   

cglib

導入jar包,cglib-nodep-().jar

JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢?
CGLIB是直接繼承代理

性能:CGLib>JDK
時間耗費:JDK時間效率高
單例的對象使用CGLib


代碼示例

public class SayHello {
 public void say(){
  System.out.println("hello everyone");
 }
} 


public class CglibProxy implements MethodInterceptor{
 private Enhancer enhancer = new Enhancer();
 public Object getProxy(Class clazz){
  //設置需要創建子類的類
  enhancer.setSuperclass(clazz);
  enhancer.setCallback(this);
  //通過字節碼技術動態創建子類實例
  return enhancer.create();
 }
 //實現MethodInterceptor接口方法
 public Object intercept(Object obj, Method method, Object[] args,
   MethodProxy proxy) throws Throwable {
  System.out.println("前置代理");
  //通過代理類調用父類中的方法
  Object result = proxy.invokeSuper(obj, args);
  System.out.println("後置代理");
  return result;
 }
}


public class DoCGLib { 
 public static void main(String[] args) { 
  CglibProxy proxy = new CglibProxy(); 
  //通過生成子類的方式創建代理類 
  SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class); 
  proxyImp.say(); 
 } 
} 

JDK動態代理的內部實現

動態代理實現思路
實現功能:通過Proxy的newProxyInstance返回代理對象
1. 聲明一段源碼(動態產生代理)
2. 編譯源碼(JDK Compiler API),產生新的類(代理類)
3. 將這個類load到內存當中,產生一個新的對象(代理對象)
4. return 代理對象

發佈了187 篇原創文章 · 獲贊 3 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章