JAVA中代理模式
代理模式
在某些情況下,一個(gè)客戶不想或者不能直接引用一個(gè)對(duì)象,此時(shí)可以通過一個(gè)稱之為“代理”的第三者來(lái)實(shí)現(xiàn)間接引用。代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到 中介的作用,并且可以通過代理對(duì)象去掉客戶不能看到 的內(nèi)容和服務(wù)或者添加客戶需要的額外服務(wù)。
簡(jiǎn)單來(lái)說(shuō)代理模式就是通過一個(gè)代理對(duì)象去訪問一個(gè)實(shí)際對(duì)象,并且可以像裝飾模式一樣給對(duì)象添加一些功能。
靜態(tài)代理
所謂靜態(tài)代理即在程序運(yùn)行前代理類就已經(jīng)存在,也就是說(shuō)我們編寫代碼的時(shí)候就已經(jīng)把代理類的代碼寫好了,而動(dòng)態(tài)代理則是在程序運(yùn)行時(shí)自動(dòng)生成代理類。
描述起來(lái)太過抽象,看一下代碼就明白是怎么回事了
接口
public interface Subject { public void aa(); }
被代理類
public class Student implements Subject { public void aa() { System.out.println("添加學(xué)生"); } }
代理類
//代理類 //與被代理類實(shí)現(xiàn)同一個(gè)接口
public class Proxy implements Subject {
private Student stu;
public void aa() {
if(stu==null){
stu=new Student();
}
//在執(zhí)行被代理對(duì)象的方法前做一些事情
System.out.println("============before");
//執(zhí)行被代理對(duì)象的方法
stu.aa();
//在執(zhí)行被代理對(duì)象的方法后做一些事
System.out.println("============after");
}
}
測(cè)試類
public class MyTest { @Test public void test1(){ Proxy proxy=new Proxy(); proxy.aa(); } }
執(zhí)行結(jié)果
============before
添加學(xué)生
============after
動(dòng)態(tài)代理
觀察以上代碼可以發(fā)現(xiàn)每一個(gè)代理類只能為一個(gè)接口服務(wù),這樣一來(lái)程序開發(fā)中必然會(huì)產(chǎn)生過多的代理,而且,所有的代理操作除了調(diào)用的方法不一樣之外,其他的操作都一樣,則此時(shí)肯定是重復(fù)代碼。解決這一問題最好的做法是可以通過一個(gè)代理類完成全部的代理功能,那么此時(shí)就必須使用動(dòng)態(tài)代理完成。
再來(lái)看一下動(dòng)態(tài)代理:
JDK動(dòng)態(tài)代理中包含一個(gè)類和一個(gè)接口:
public interface IUserDao { public void add(); }
public class UserDaoImpl implements IUserDao { public void add() { System.out.println("添加學(xué)生"); } }
測(cè)試
//JDK動(dòng)態(tài)代理 @Test public void testOne(){ final IUserDao dao=new UserDaoImpl(); InvocationHandler in=new InvocationHandler() { /** * * @param proxy 代理對(duì)象 * @param method 目標(biāo)對(duì)象的方法 * @param args 目標(biāo)對(duì)象方法的參數(shù) * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("==========before"); Object result = method.invoke(dao, args); System.out.println("==========after"); return result; } };
//Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
IUserDao proxy = (IUserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(),in);
proxy.add(); }
參數(shù)說(shuō)明:
Object proxy:指被代理的對(duì)象。
Method method:要調(diào)用的方法
Object[] args:方法調(diào)用時(shí)所需要的參數(shù)
可以將InvocationHandler接口的子類想象成一個(gè)代理的最終操作類,
//Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)參數(shù)說(shuō)明
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實(shí)例
Ps:類加載器
在Proxy類中的newProxyInstance()方法中需要一個(gè)ClassLoader類的實(shí)例,ClassLoader實(shí)際上對(duì)應(yīng)的是類加載器,在Java中主要有一下三種類加載器;
Booststrap ClassLoader:此加載器采用C++編寫,一般開發(fā)中是看不到的;
Extendsion ClassLoader:用來(lái)進(jìn)行擴(kuò)展類的加載,一般對(duì)應(yīng)的是jre\lib\ext目錄中的類;
AppClassLoader:(默認(rèn))加載classpath指定的類,是最常使用的是一種加載器。
動(dòng)態(tài)代理
與靜態(tài)代理類對(duì)照的是動(dòng)態(tài)代理類,動(dòng)態(tài)代理類的字節(jié)碼在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無(wú)需程序員手工編寫它的源代碼。動(dòng)態(tài)代理類不僅簡(jiǎn)化了編程工作,而且提高了軟件系統(tǒng)的可擴(kuò)展性,因?yàn)镴ava 反射機(jī)制可以生成任意類型的動(dòng)態(tài)代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動(dòng)態(tài)代理類的能力。
但是,JDK的動(dòng)態(tài)代理依靠接口實(shí)現(xiàn),如果有些類并沒有實(shí)現(xiàn)接口,則不能使用JDK代理,這就要使用cglib動(dòng)態(tài)代理了。
Cglib動(dòng)態(tài)代理
JDK的動(dòng)態(tài)代理機(jī)制只能代理實(shí)現(xiàn)了接口的類,而不能實(shí)現(xiàn)接口的類就不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理,cglib是針對(duì)類來(lái)實(shí)現(xiàn)代理的,他的原理是對(duì)指定的目標(biāo)類生成一個(gè)子類,并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對(duì)final修飾的類進(jìn)行代理。
public interface IUserDao { public void add(); }
public class UserDaoImpl {
- /**
- * 這個(gè)是沒有實(shí)現(xiàn)接口的實(shí)現(xiàn)類
- *
- * @author student
- *
- */
public void add() { System.out.println("添加學(xué)生"); } }
測(cè)試類
//Cglib動(dòng)態(tài)代理 @Test public void test1(){ //創(chuàng)建目標(biāo)對(duì)象 final UserDaoImpl impl=new UserDaoImpl(); //創(chuàng)建一個(gè)代理對(duì)象 Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(impl.getClass()); enhancer.setCallback(new MethodInterceptor() { /** * * @param o 代理對(duì)象 * @param method 目標(biāo)對(duì)象方法 * @param objects 目標(biāo)對(duì)象方法參數(shù) * @param methodProxy 代理類的方法 * @return * @throws Throwable */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("==============before"); Object result = method.invoke(impl, objects); System.out.println("==============after"); return result; } }); UserDaoImpl proxy = (UserDaoImpl) enhancer.create(); proxy.add(); }
posted on 2017-03-28 14:32 川哥哥 閱讀(196) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)