記錄學習的每一點過程
本文主要介紹的是動態代理,所以靜態代理在這里就簡單介紹一下
1、靜態代理
靜態代理的角色介紹
抽象角色:一般是接口或者是抽象類
1 /** 2 * 抽象角色:以租房為例,這是一個租房子的接口 3 */ 4 public interface Rent { 5 void rent(); 6 }
真實角色:被代理的角色
1 /** 2 * 文件名:Host 3 * 作 者:zyz 4 * 時 間:2019/6/12 9:47 5 * ------------------------- 6 * 功能和描述:真實角色,實現抽象角色對應的接口(Rent) 7 **/ 8 public class Host implements Rent{ 9 public void rent(){ 10 System.out.println("房屋出租"); 11 } 12 }
代理角色:代理真實角色,代理真實角色之后,一般會做一些附屬(增強的操作)
1 /** 2 * 代理角色:同真實角色實現同一個接口 3 */ 4 public class Proxy implements Rent { 5 private Host host; 6 7 public Proxy() { 8 } 9 10 public Proxy(Host host) { 11 this.host = host; 12 } 13 14 public void setHost(Host host) { 15 this.host = host; 16 } 17 18 public void rent() { 19 seeHouse(); 20 host.rent(); 21 fee(); 22 } 23 24 25 //**************代理角色附帶(增強)的一些功能**************// 26 private void seeHouse(){ 27 System.out.println("帶租客看房子"); 28 } 29 private void fee(){ 30 System.out.println("收取中介費"); 31 } 32 }
測試類
1 /** 2 * 文件名:Client 3 * 作 者:zyz 4 * 時 間:2019/6/12 9:47 5 * ------------------------- 6 * 功能和描述: 7 **/ 8 9 public class Client { 10 public static void main(String[] args) { 11 //定義一個真實角色 12 Host host = new Host(); 13 //定義代理角色 14 Proxy proxy = new Proxy(host); 15 //使用代理角色的實例去實現具體操作 16 proxy.rent(); 17 } 18 }
靜態代理總結
優點:
使真實角色處理的業務更加的純粹,不再關注一些公共的事;
公共的業務由代理來完成,實現了業務的分工;
公共業務的擴展變得更加集中和方便
缺點:
類變多了,多了代理類,工作量變大了,且不易擴展
解決此問題的方案就是使用動態代理
2、動態代理
還是以租房子為例,因為在學習階段,越是簡單的例子越是容易理解,博主在學習的時候看到了好幾篇文章光看代碼就暈頭轉向的了,還沒學習動態代理就已經蒙了。所以我這邊舉得例子基本都是大家常見的,代碼簡單,但是能將知識點介紹的很透徹。
動態代理有兩種實現方式:一種是基於jdk的動態代理,一種是基於cglib的動態代理
基於jdk的動態代理
基於jdk的動態代理的特點是必須要有接口,記住一個類Proxy(java.lang.reflect.Proxy,別導錯包)和一個接口InvocationHandler,廢話少說,直接上代碼
第一步:新建一個接口Rent
1 public interface Rent { 2 void rent(); 3 }
第二步:新建一個類(Host),實現該接口(Rent)
1 public class Host implements Rent{ 2 public void rent(){ 3 System.out.println("房屋出租"); 4 } 5 }
第三步:新建一個代理類,實現InvocationHandler接口
1 public class RentInvocationHandler implements InvocationHandler { 2 3 private Object object; 4 5 public RentInvocationHandler(Object object) { 6 this.object = object; 7 } 8 9 /** 10 * @param proxy:代理類 11 * @param method:代理類調用處理程序的方法對象 12 * @param args:方法的參數 13 */ 14 @Override 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("使用動態代理做的一些增強的操作......"); 17 //第一個參數表示真實對象 18 //第二個參數表示參數 19 Object result = method.invoke(object, args); 20 21 return result; 22 } 23 }
完工就是這么easy,下面開始測試
1 public class Client { 2 public static void main(String[] args) { 3 //定義一個真實對象 4 Host host = new Host(); 5 //創建代理類 6 RentInvocationHandler pih = new RentInvocationHandler(host); 7 //利用Proxy.newProxyInstance生成代理類 8 //第一個參數:真實類對象的類加載器 9 //第二個參數:真實類對象的所有的接口 10 //第三個參數:代理類對象 11 Rent p = (Rent)Proxy.newProxyInstance(host.getClass().getClassLoader(),host.getClass().getInterfaces(),pih); 12 p.rent(); 13 14 } 15 }
輸出:

再次強調一點:在調用的時候
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
只要搞清楚這里面的三個參數是干嘛的就OK
基於CGLib的動態代理
基於CGLib的動態代理是沒有接口的限制的,行了,直接擼代碼(雖然有重復的代碼,但是為了讓讀者能夠看的清晰,每一步我都會寫出來)
第一步:創建一類真實類Host_CGLib
1 public class Host_CGLib { 2 public void rent(){ 3 System.out.println("租房子......CGLib"); 4 } 5 }
第二步:創建一個攔截器類實現MethodInterceptor(net.sf.cglib.proxy.MethodInterceptor)接口
1 public class RentMethodInterceptor implements MethodInterceptor { 2 @Override 3 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 4 System.out.println("使用CGLib方式做的增強......"); 5 Object result = methodProxy.invokeSuper(o, objects); 6 return result; 7 } 8 }
OK搞定,開始測試
1 public class CGLibTest { 2 public static void main(String[] args) { 3 //設置增強需要用到的類 4 Enhancer enhancer = new Enhancer(); 5 //設置需要增強的類(這里是Host_CGLib類) 6 enhancer.setSuperclass(Host_CGLib.class); 7 //設置需要回調的攔截器 8 enhancer.setCallback(new RentMethodInterceptor()); 9 //生成對應的增強類 10 Host_CGLib host = (Host_CGLib)enhancer.create(); 11 host.rent(); 12 } 13 }
輸出:

總結:對於底層和原理這邊並沒有介紹,至於為什么沒有介紹(因為我也不會),因為初學者先知道怎么用就行,不是什么東西都是刨根問底的,現在知道是什么,再是搞為什么吧。熟悉了以后在此基礎上去深挖,這才是王道。 如果您覺得我寫的文章您看明白了,請動動您的小手,將文章分享給您的好友哦!