java動態(tài)代理模式初解 收藏
第一部分 1.代理模式的作用和定義: 為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用。 2.代理模式中涉及的角色 抽象角色:聲明真實對象和代理對象的共同接口;一般聲明為抽象類或是接口. 代理角色:代理對象角色內(nèi)部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理對象可以在執(zhí)行真實對象操作時,附加其他的操作,相當(dāng)于對真實對象進(jìn)行封裝。 真實角色:代理角色所代表的真實對象,是我們最終要引用的對象。 3.針對三種角色舉個例子 抽象角色 package proxypattern; public interface Subject ...{
public void dothing(); } 真實角色,實現(xiàn)了Subject 的dothing()方法; package proxypattern; public class RealSubject implements Subject...{
public RealSubject()...{ } public void dothing()...{ System.out.println("Do you want do."); } }代理角色: package proxypattern; public class ProxySubject implements Subject...{
public RealSubject realSubject; public ProxySubject()...{ } public void dothing()...{ predothing(); if(realSubject==null)...{ realSubject=new RealSubject(); } realSubject.dothing(); //執(zhí)行真實對象的dothing()方法 afterdothing(); } private void predothing()...{ System.out.println("before you do thing!"); } private void afterdothing()...{ System.out.println("after you do thing!"); } }
測試事例 package proxypattern; public class ProxyTest ......{
/** *//** *//** *//**
* @param args */ public static void main(String[] args) ......{ Subject sub=new ProxySubject(); sub.dothing();
} }4.如果要按照上述的方法使用代理模式,那么真實角色必須是事先已經(jīng)存在的,并將其作為代理對象的內(nèi)部屬性。但是實際使用時,一個真實角色必須對應(yīng)一個代理角色,如果大量使用會導(dǎo)致類的急劇膨脹;此外,如果事先并不知道真實角色,該如何使用代理呢?這個問題可以通過Java的動態(tài)代理類來解決5.如果要按照上述的方法使用代理模式,那么真實角色必須是事先已經(jīng)存在的,并將其作為代理對象的內(nèi)部屬性。但是實際使用時,一個真實角色必須對應(yīng)一個代理角色,如果大量使用會導(dǎo)致類的急劇膨脹;此外,如果事先并不知道真實角色,該如何使用代理呢?這個問題可以通過Java的動態(tài)代理類來解決
第二部分
.動態(tài)代理類 Java動態(tài)代理類位于Java.lang.reflect包下,一般主要涉及到以下兩個類:
(1). Interface InvocationHandler:該接口中僅定義了一個方法Object:invoke(Object obj,Method method, Object[] args)。在實際使用時,第一個參數(shù)obj一般是指代理類,method是被代理的方法,如上例中的dothing(),args為該方法的參數(shù)數(shù)組。 這個抽象方法在代理類中動態(tài)實現(xiàn)。
(2).Proxy:該類即為動態(tài)代理類,作用類似于上例中的ProxySubject,其中主要包含以下內(nèi)容: Protected Proxy(InvocationHandler h):構(gòu)造函數(shù),估計用于給內(nèi)部的h賦值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中l(wèi)oader是類裝載器,interfaces是真實類所擁有的全部接口的數(shù)組。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個實例,返回后的代理類可以當(dāng)作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)。
所謂Dynamic Proxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后該class就宣稱它實現(xiàn)了這些 interface。你當(dāng)然可以把該class的實例當(dāng)作這些interface中的任何一個來用。當(dāng)然啦,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質(zhì)性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。
代理角色
package dynamicproxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class DynamicSubject implements InvocationHandler ...{
public DynamicSubject() ...{ } public DynamicSubject(Object obj) ...{ sub = obj; } private Object sub; public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable ...{ // TODO Auto-generated method stub System.out.println("before you do thing"); method.invoke(sub, args); System.out.println("after you do thing"); return null; } }
該代理類的內(nèi)部屬性為Object類,實際使用時通過該類的構(gòu)造函數(shù)DynamicSubject(Object obj)對其賦值;此外,在該類還實現(xiàn)了invoke方法,該方法中的 method.invoke(sub,args);
其實就是調(diào)用被代理對象的將要被執(zhí)行的方法,方法參數(shù)sub是實際的被代理對象,args為執(zhí)行被代理對象相應(yīng)操作所需的參數(shù)。通過動態(tài)代理類,我們可以在調(diào)用之前或之后執(zhí)行一些相關(guān)操作。
調(diào)用事例
package dynamicproxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; import proxypattern.RealSubject;
import proxypattern.Subject; public class Client ...{
/** *//**
* @param args */ public static void main(String[] args) throws Throwable...{ // TODO Auto-generated method stub RealSubject rs=new RealSubject(); InvocationHandler ds=new DynamicSubject(rs); Class cls=rs.getClass(); Subject subject=(Subject)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds); subject.dothing(); } }
通過這種方式,被代理的對象(RealSubject)可以在運行時動態(tài)改變,需要控制的接口(Subject接口)可以在運行時改變,控制的方式(DynamicSubject類)也可以動態(tài)改變,從而實現(xiàn)了非常靈活的動態(tài)代理關(guān)系。
cglib
cglib實現(xiàn)AOP CGLib 與java標(biāo)準(zhǔn)庫提供的實現(xiàn)方案不同,cglib主要是基于實現(xiàn)類(如StudentInfoServiceImpl.java)擴展一個子類 來實現(xiàn)。與Dynamic Proxy中的Proxy和InvocationHandler相對應(yīng),net.sf.cglib.proxy.Enhancer和 MethodInterceptor在CGLib中負(fù)責(zé)完成代理對象創(chuàng)建和方法截獲處理,產(chǎn)生的是目標(biāo)類的子類而不是通過接口來實現(xiàn)方法攔截的, Enhancer主要是用于構(gòu)造動態(tài)代理子類來實現(xiàn)攔截,MethodInterceptor(擴展了Callback接口)主要用于實現(xiàn)around advice(AOP中的概念): 1)我們的業(yè)務(wù)處理(StudentInfoServiceImpl.java):
public class StudentInfoServiceImpl{ public void findInfo(String name){ System.out.println("你目前輸入的名字是:"+name); } } 2)實行一個工具來處理日志功能(AOPInstrumenter.java): import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import org.apache.log4j.Logger; public class AOPInstrumenter implements MethodInterceptor{ private Logger log=Logger.getLogger(AOPInstrumenter.class); private Enhancer enhancer=new Enhancer(); public Object getInstrumentedClass(Class clz){ enhancer.setSuperclass(clz); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable{ log.info("調(diào)用日志方法"+method.getName()); Object result=proxy.invokeSuper(o,args); return result; } } 3)我們來測試一下(AOPTest.java): public class AOPTest{ public static void main(String[] args){ AOPInstrumenter instrumenter=new AOPInstrumenter(); StudentInfoServiceImpl studentInfo=(StudentInfoServiceImpl)instrumenter.getInstrumentedClass(StudentInfoServiceImpl.class); studentInfo.findInfo("阿飛"); } } 輸出結(jié)果與以上相同。 CGLib中為實現(xiàn)以上目的,主要提供的類 1)Enhancer:setCallback(Callback) ,setSuperclass(Class) ,create()返回動態(tài)子類Object 2)MethodInterceptor必須實現(xiàn)的接口:intercept(Object,Method,Object[],MethodProxy)返回的是原方法調(diào)用的結(jié)果。和Proxy原理一樣。 本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/oscar999/archive/2007/08/03/1724039.aspx |
|
來自: yfm10 > 《設(shè)計模式》