動(dòng)態(tài)代理的意義在于生成一個(gè)代理對(duì)象,來(lái)代理真實(shí)對(duì)象,從而控制真實(shí)對(duì)象的訪問(wèn)。比如你是以為軟件工程師,客戶帶著需求去找公司,顯然不會(huì)直接和你談,而是去找商務(wù),此時(shí)客戶認(rèn)為商務(wù)就代表公司。商務(wù)(代理對(duì)象)的意義在于可以進(jìn)行談判,比如軟件的價(jià)格,交付,進(jìn)度的時(shí)間節(jié)點(diǎn),項(xiàng)目完成后追討應(yīng)收賬款等。
所以說(shuō),代理的作用就是,在真實(shí)的對(duì)象訪問(wèn)之前或者之后加入對(duì)應(yīng)的邏輯,或者根據(jù)其他規(guī)則控制是否使用真實(shí)對(duì)象。
因此,代理必須分為兩個(gè)步驟:
代理對(duì)象和真實(shí)對(duì)象建立代理關(guān)系
實(shí)現(xiàn)代理對(duì)象的代理邏輯方法
在java中有多種動(dòng)態(tài)代理技術(shù),比如JDK,CGLIB,Javassist等。
一,JDK動(dòng)態(tài)代理。
這是JDK自帶的功能,它必須借助一個(gè)接口才能產(chǎn)生代理對(duì)象,所以先定義接口。
定義接口:
package proxy;public interface HelloWorld { public void sayHelloWorld();}
然后提供實(shí)現(xiàn)類,來(lái)實(shí)現(xiàn)接口:
package proxy;public class HelloWorldImpl implements HelloWorld { @Override public void sayHelloWorld() { System.out.println("Hello World"); }}
接下來(lái)就可以開(kāi)始動(dòng)態(tài)代理了。在JDK動(dòng)態(tài)代理中,要實(shí)現(xiàn)代理邏輯類,必須去實(shí)現(xiàn)java.lang.reflect.InvocationHandler類,它里面定義了一個(gè)invoke方法。
實(shí)現(xiàn)代理邏輯類如下:
package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JdkProxyExample implements InvocationHandler { // 真實(shí)對(duì)象 private Object target = null; /** * 建立代理對(duì)象和真實(shí)對(duì)象的代理關(guān)系,并返回代理對(duì)象 * * @param target真實(shí)對(duì)象 * @return 代理對(duì)象 */ public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理方法邏輯 * * @param proxy * --代理對(duì)象 * @param method * --當(dāng)前調(diào)度方法 * @param args * --當(dāng)前方法參數(shù) * @return 代理結(jié)果返回 * @throws Throwable * 異常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("進(jìn)入代理邏輯方法"); System.out.println("在調(diào)度真實(shí)對(duì)象之前的服務(wù)"); Object obj = method.invoke(target, args);// 相當(dāng)于調(diào)用sayHelloWorld方法 System.out.println("在調(diào)度真實(shí)對(duì)象之后的服務(wù)"); return obj; }}
Proxy.newProxyInstance方法的三個(gè)參數(shù)分別為:target本身的類加載器,target實(shí)現(xiàn)的接口,實(shí)現(xiàn)方法邏輯的代理類。
測(cè)試代碼如下:
package proxy;import reflect.ReflectServiceImpl;public class ProxyTest { public static void main(String[] args) { JdkProxyExample jdk = new JdkProxyExample(); // 綁定關(guān)系,因?yàn)閽煸诮涌贖elloWorld下,所以聲明代理對(duì)象HelloWorld proxy HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl()); // 注意,此時(shí)HelloWorld對(duì)象已經(jīng)是一個(gè)代理對(duì)象,它會(huì)進(jìn)入代理的邏輯方法invoke里 proxy.sayHelloWorld(); }}
二,CGLB動(dòng)態(tài)代理、
他的優(yōu)勢(shì)在于不需要提供接口,只需要一個(gè)非抽象類就可以實(shí)現(xiàn)動(dòng)態(tài)代理。代碼所引用的的jar包:cglib-3.2.5.jar,asm-5.0.4.jar
需要代理的類:
package proxy;public class CglibHelloWorld { public void sayHello(String name) { System.err.println("Hello " + name); }}
實(shí)現(xiàn)代理邏輯的類:
package proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxyExample implements MethodInterceptor { /** * 生成CGLIB代理對(duì)象 * * @param cls * -- Class類 * @return Class類的CGLIB代理對(duì)象 */ public Object getProxy(Class cls) { // CGLIB enhancer增強(qiáng)類對(duì)象 Enhancer enhancer = new Enhancer(); // 設(shè)置增強(qiáng)類型 enhancer.setSuperclass(cls); // 定義代理邏輯對(duì)象為當(dāng)前對(duì)象,要求當(dāng)前對(duì)象實(shí)現(xiàn)MethodInterceptor方法 enhancer.setCallback(this); // 生成并返回代理對(duì)象 return enhancer.create(); } /** * 代理邏輯方法 * * @param proxy * 代理對(duì)象 * @param method * 方法 * @param args * 方法參數(shù) * @param methodProxy * 方法代理 * @return 代理邏輯返回 * @throws Throwable異常 */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.err.println("調(diào)用真實(shí)對(duì)象前"); // CGLIB反射調(diào)用真實(shí)對(duì)象方法 Object result = methodProxy.invokeSuper(proxy, args); System.err.println("調(diào)用真實(shí)對(duì)象后"); return result; }}
測(cè)試代碼:
package proxy;public class ProxyTest { public static void main(String[] args) { CglibProxyExample cpe = new CglibProxyExample(); CglibHelloWorld obj = (CglibHelloWorld)cpe.getProxy(CglibHelloWorld.class); obj.sayHello("張三"); }}
三,參考資料
《java EE 互聯(lián)網(wǎng)框架整合開(kāi)發(fā)》 楊開(kāi)振 著
聯(lián)系客服