代理模式的由來:當調用某個對象時,不關心是否準確獲得該對象,而是隻要一個能提供對應功能的對象便可,這時咱們能夠爲該對象提供一個代理對象,由代理對象控制對源對象的引用。java
第一.靜態代理數組
常見靜態代理模式:一個接口,兩個實現類,分別爲被代理類和代理類,代理類中進行以下操做便可
1.建立接口類型成員變量
2.構造方法中建立被代理類對象()
3.實現的接口方法中調用被代理類的實現的接口方法
示例代碼以下:ide
// 被代理類 class SubjectImpl implements Subject { @Override public void action() { System.out.println("執行action方法體"); } } // 代理類 class ProxyClass implements Subject { private Subject subject = new SubjectImpl(); private void beforeHandle() { System.out.println("業務方法執行前執行前置加強處理"); } private void afterHandle() { System.out.println("業務方法執行後執行後置加強處理"); } @Override public void action() { this.beforeHandle(); subject.action(); this.afterHandle(); } } public class ProxyTest { public static void main(String[] args) { ProxyClass obj = new ProxyClass(); obj.action(); } }
要使用被代理類對象的方法時,只需簡單的實例化代理類對象,調用此代理類對象的方法便可,實際上是方法內部調用了被代理類的方法。工具
第二.動態代理this
JDK動態代理主要用到了Proxy類和InvocationHandler接口,二者都在java.lang.reflect包下。spa
首先介紹一下Proxy類,這個類是全部動態代理類的父類,主要用到這個類的newProxyInstance()靜態方法:代理
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
這個方法直接生成一個動態代理類對象,方法須要傳三個參數,第一個參數是被代理類對應的類加載器對象,第二個參數是被代理類實現的一系列接口對應的Class對象組成的數組一個數組,第三個參數是一個InvocationHandler對象(一個InvocationHandler實現類對象)。code
InvocationHander接口就只有一個方法:對象
public Object invoke(Object proxy, Method method, Object[] args)
咱們得自定義一個InvocationHander接口實現類,重寫invoke()方法。blog
JDK動態代理代碼示例:
//接口 interface Subject { public void doSomething(String str); } // 接口實現類 class RealSubject implements Subject { @Override public void doSomething(String str) { System.out.println("Subject接口實現類RealSubject實現doSomething方法()"); } } // InvocationHandler接口實現類 class MyIncovationHandler implements InvocationHandler { private Object proxied; // 構造器參數是被代理類對象 public MyIncovationHandler(Object proxied) { this.proxied = proxied; } public MyIncovationHandler() { } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); method.invoke(proxied, args); after(); return null; } // 加強處理方法,能夠抽出到一個單獨的工具類裏面 private void before() { System.out.println("Before處理"); } private void after() { System.out.println("After處理"); } } public class JdkDynamicProxyTest { public static void main(String args[]) { Subject s = new RealSubject(); Object obj = Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), new MyIncovationHandler(s)); Subject subject = (Subject) obj; subject.doSomething("kou"); } }
上例中,有一個RealSubject類,實現了接口Subject。InvocationHander接口的實現類MyInvocationHander,重寫了invoke方法,在方法體中調用第二個參數method的invoke方法,method的invoke方法須要兩個參數,第一個參數是被代理類的實例,第二個參數是參數列表,是invoke方法的第三個參數。這裏被代理類的實例不建議直接new出來一個實例而後傳進去,而是建議在建立InvocationHander實例時把被代理類實例傳進來,這樣比較解耦。
編譯上Proxy.newProxyInstance()的返回值類型是Object,但其實運行時類型是動態代理類的類型($Proxy開頭的類),又由於實現了代理類所實現的所有接口,因此能夠強轉爲任意一個所實現的接口類型。這個時候調用該接口的方法,底層就會執行接口實現類對應的實現。
Proxy的newProxyInstance()方法的第二個參數是接口對應的Class對象組成的數組,而不是被代理類的Class對象。因此說,JDK動態代理創建在接口之上的。那麼,若是被代理類沒有實現任何接口,就不能用JDK動態代理了,須要用到cglib動態代理。cglib動態代理實際上是對被代理類建立一個子類,讓這個子類去代理父類,因此要求被代理類不能是final的。