靜態代理與靜態代理

1 代理模式及概念

    代理模式是給某個對象提供一個代理對象,並由代理對象控制對原始對象的引用。以下圖:     代理模式java

    代理類和委託類有共同的父類,這樣在任何使用原始對象(委託對象)的地方均可用代理對象替代。代理對象負責請求的預處理、過濾,將請求分派給原始對象,執行原始對象執行結束後的後續處理。spring

    所謂靜態代理,是指在程序運行前,就已經存在代理類的字節碼文件,代理類和原始類(委託類)的關係在運行前就已肯定。編程

    所謂動態代理,是指在程序運行期間,由JVM根據反射機制動態生成代理類的字節碼文件,代理類和原始類(委託類)的關係是在運行時肯定的。ide

2 靜態代理

2.1 編寫代理模式實現靜態代理

    編寫代理模式,便可實現靜態代理。但這樣的話,有多少個委託類,就須要編寫多少個代理類,即便代理邏輯是相同的。而以AspectJ爲代理的靜態代理,以及JDK動態代理、CGLib動態代理均可以解決這個問題,使得僅需在一個地方編寫代理邏輯,這也是AOP思想和目的。工具

2.2 以AspectJ爲表明的靜態代理

    AspectJ是Java語言的一個AOP實現,主要包括兩個部分:第一個部分定義瞭如何表達、定義AOP編程中的語法規範,經過這套語言規範,咱們能夠方便地用 AOP 來解決Java語言中存在的交叉關注點問題;另外一個部分是工具部分,包括編譯器、調試工具等。this

    Aspectj實現了獨有的編譯器,在編譯時生成代理類文件。有關AspectJ的用法,參考http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/代理

3 動態代理

    Spring AOP的核心就是動態代理。Spring動態代理有兩種實現方式:JDK動態代理和CGLib動態代理,Spring會根據實際狀況自行選擇採用哪一種方式。調試

3.1 JDK動態代理

    JDK的動態代理,是基於接口的動態代理。Java API提供以下兩個類幫助咱們實現動態代理:code

  • java.lang.reflect.Proxy,這是Java動態代理機制生成的全部動態代理類的父類,它提供靜態方法來爲一組接口動態地生成代理類及其對象。
  • java.lang.reflect.InvocationHandler,這是調用處理器接口,它自定義了一個invoke方法,用於實現代理邏輯、轉發請求給對原始類對象。

如下是java動態代理編寫示例:對象

/**
 * 主題接口
 */
public interface Subject {
    public void hello();
}
/**
 * 委託類或原始類
 */
public class DelegateSubject implements Subject {
    public void hello(){
        System.out.println("Hello, Word!");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 調用處理器,負責實現代理邏輯、轉發請求給委託對象
 */
public class SubjectInvocationHandler implements InvocationHandler {

    //代理類持有一個委託類的對象引用
    private Object delegate;

    public SubjectInvocationHandler(Object delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long stime = System.currentTimeMillis();
        System.out.println(">>begin: "+stime);

        //利用反射機制將請求轉發給委託類處理,method.invoke返回Object對象做爲方法執行結果。
        //由於委託類的相應方法程序沒有返回值,因此這裏不處理返回值
        method.invoke(delegate, args);
        long etime = System.currentTimeMillis();
        System.out.println(">>end: "+etime);

        System.out.println("執行任務耗時" + (etime - stime) + "毫秒。");
        return null;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 生成代理對象的工廠類
 */
public class DynProxyFactory {

    // 客戶端調用此工廠方法得到代理對象,它並不知道返回的是代理類對象仍是委託類對象。
    public static Subject getInstance() {
        Subject delegate = new DelegateSubject();
        InvocationHandler handler = new SubjectInvocationHandler(delegate);
        Subject proxy = (Subject) Proxy.newProxyInstance(
                delegate.getClass().getClassLoader(),
                delegate.getClass().getInterfaces(),
                handler);
        return proxy;
    }
}
/**
 * 客戶端
 */
public class Client {

    public static void main(String[] args) {
        Subject proxy = DynProxyFactory.getInstance();
        proxy.hello();
    }
}

3.2 CGLib動態代理

    儘管java API能夠幫助咱們方便的實現動態代理,但因爲生成的代理類已經繼承了共同的父類(java.lang.reflect.Proxy),這就使得代理類沒法再繼承其它類,而只能實現接口。也就是說,JDK的動態代理機制只能代理實現了接口的類,而沒有實現接口的類就不能代理。

    若是要實現對類的動態代理,那就要用CGLib,它的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。

4 Spring AOP與AspectJ

    雖然Spring AOP採用了JDK動態代理和CGLib動態代理,但Spring 容許用AspectJ Annotation來定義方面(Aspect)、切入點(Pointcut)和加強處理(Advice), 而不須要使用AspectJ的編譯器和織入器。

相關文章
相關標籤/搜索