代理模式概述
代理模式是為了提供額外或不同的操作,而插入的用來替代”實際”對象的對象,這些操作涉及到與”實際”對象的通信,因此代理通常充當中間人角色。
java中常用的動態代理模式為jdk動態代理和cglib動態代理。
反射技術
了解動態代理之前,需要先了解一下java中的反射,反射在框架中的應用非常廣泛,它能夠配置:類的全限定名,方法和參數。在運行時,動態的完成類的初始化,或者反射調用某些方法。
我們可以通過Class.forName()方法加載類,並用getConstructor方法配置參數。例:
object = (goodsServiceImpl)=Class.forName("com.xjx.test.goodsServiceImpl").getConstructor(String.class).newInstance("計算機");
1. jdk動態代理舉例
jdk動態代理由java.lang.reflect.*包提供,它必須借助一個接口才能實現代理。
我們舉個例子來實現jdk動態代理並簡要分析:
首先我們定義一個接口:
public interface jdkProxy { public void test(String tString); }
以及它的實現類:
public class jdkProxyImpl implements jdkProxy{ @Override public void test(String tString) { // TODO Auto-generated method stub
System.out.println("代理內方法"+tString); } }
接下來我們要進行代理。代理過程分2步:
1.建立起代理對象和真實服務對象之間的關系,生產代理對象;
2.實現邏輯的代理;
在jdk動態代理中,要實現代理邏輯就必須實現InvocationHandler接口。它里面定義了一個invoke方法,每當我們通過代理對象調用方法時,它都會被轉發到這個invoke方法,我們來
定義一個實現代理邏輯的類:
public class jdkProxyExample implements InvocationHandler{ //真實對象
private Object target = null; /** * 建立真實對象和代理對象的代理關系 * @param target真實對象 * @return 代理對象 */
public Object setTargetAndBind(Object target) { this.target = target; /** * 參數1:getClassLoader()提供類加載器;
參數2:getInterfaces()要掛載動態代理對象的接口,就是target的接口; */
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this); } /** * 代理方法邏輯 * @param:代理對象 * method:當前調度方法 * args:當前方法參數 * return 代理結果返回 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("進入代理對象方法,在此執行代理對象之前的一些操作"); //執行目標對象中的某個方法
Object object = method.invoke(target, args); System.out.println("調用代理對象方法之后的操作"); return object; } }
1.1 生成一個代理對象
setTargetAndBind()這個方法內的newProxyInstance()方法通過傳入被代理內,再通過反射,生成一個代理類。
1.2 實現代理類的邏輯方法
object obj = method.invoke(target,args),這個方法相當於調度真實對象的方法,只不過是通過反射區實現。它返回方法的執行結果。
並且在invoke方法里,可以在調用真實對象方法之前和之后做一些其他的操作,這也是AOP的實現原理。
這樣,一個jdk動態代理就完成了,接下來可以寫個測試類測試一下:
public class jdkProxyExampleTest { @Test public void testProxy() { jdkProxyExample jdkProxyExample = new jdkProxyExample(); //綁定關系,此時jdkProxy已經是一個代理對象 jdkProxy jdkProxy = (jdkProxy)jdkProxyExample.setTargetAndBind(new jdkProxyImpl()); //執行代理對象方法 jdkProxy.test("動態代理jdk"); } }
打印結果如下:
2. 為什么jdk動態代理一定需要目標對象實現接口?(可能有誤)
1.我們可以看到,在綁定關系的方法中,實現被代理類的反射,需要我們提供接口,然后它通過接口實現代理類。沒有它就找不到反射的方法。
2.由於java的單繼承機制:首先jdk動態代理是通過newInstance動態的生成代理對象的,newInstance通過ProxyGenerator生成的字節碼代表的類繼承了Proxy類:
public final class $Proxy0 extends Proxy implements jdkProxy{ ... }
$Proxy0這個類通過反編譯獲得,它就是jdkProxy的實現類的動態的代理類。
由於java的單繼承機制,被代理對象不能再被其他的類繼承,那么我們如果想建立代理類和被代理類之間的關系,只能通過實現同一個接口了。