java動態代理詳解


 

記錄學習的每一點過程

本文主要介紹的是動態代理,所以靜態代理在這里就簡單介紹一下

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 }
輸出:

 

總結:對於底層和原理這邊並沒有介紹,至於為什么沒有介紹(因為我也不會),因為初學者先知道怎么用就行,不是什么東西都是刨根問底的,現在知道是什么,再是搞為什么吧。熟悉了以后在此基礎上去深挖,這才是王道。

如果您覺得我寫的文章您看明白了,請動動您的小手,將文章分享給您的好友哦!

  

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM