Java的動態代理(DynamicProxy)

代理的概述

       代理是一種經常使用的設計模式,其目的就是爲其餘對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。html

代理模式UML圖:java

 

 

爲了保持行爲的一致性,代理類和委託類一般會實現相同的接口,因此在訪問者看來二者沒有絲毫的區別。經過代理類這中間一層,能有效控制對委託類對象的直接訪問,也能夠很好地隱藏和保護委託類對象,同時也爲實施不一樣控制策略預留了空間,從而在設計上得到了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。編程

動態代理的使用場景

動態代理的好處是它比較靈活,能夠在運行的時候才切入改變類的方法,而不須要預先定義它。設計模式

動態代理通常咱們比較少去手寫,但咱們用得其實很是多。dom

在Spring項目中用的註解,例如依賴注入的@Bean、@Autowired,事務註解@Transactional等都有用到,ide

換言之就是Srping的AOP(切面編程)。函數

這種場景的使用是動態代理最佳的落地點,能夠很是靈活地在某個類,某個方法,某個代碼點上切入咱們想要的內容,就是動態代理其中的內容。測試

靜態代理

代理類和被代理類 實現同一個接口this

缺點就是一個代理類只能針對一個接口spa

1 package Proxy.staticProxy;
2 
3 /**
4  * 建立Person接口
5  */
6 public interface Person {
7     // 交錢的方法
8     void giveMoney();
9 }
package Proxy.staticProxy;

/**
* 須要代理的對象:
*
* 學生類
*/
public class Student implements Person {
private String name;

public Student(String name) {
this.name = name;
}

@Override
public void giveMoney() {

System.out.println(name + "交保護費50");
}
}
 1 package Proxy.staticProxy;
 2 
 3 /**
 4  * 學生代理類,也實現了Person接口,保存一個學生實體,這樣既能夠代理學生產生行爲
 5  */
 6 public class StudentsProxy implements Person {
 7 
 8     //被代理的學生
 9     Student stu;
10 
11 
12     public StudentsProxy(Person stu) {
13         //只代理學生對象
14         if (stu.getClass() == Student.class) {
15             this.stu = (Student) stu;
16         }
17     }
18 
19     //代理上交保護費,調用被代理學生的交保護費行爲
20     @Override
21     public void giveMoney() {
22         stu.giveMoney();
23     }
24 }
 1 package Proxy.staticProxy;
 2 
 3 public class StaticProxyTest {
 4     public static void main(String[] args) {
 5 
 6         Person zhangsan = new Student("張三");
 7         Person moneitor = new StudentsProxy(zhangsan);
 8         moneitor.giveMoney();
 9         /**
10          * 運行結果:
11          * 
12          * 張三交保護費50
13          */
14     }
15 }

 

動態代理

動態代理分爲兩種 jdk 和 cglib

jdk

jdk 代理主要用到了

接口InvocationHandler 此接口只有一個方法(代碼以下)

InvocationHandler的實現類能夠理解成具體的代理實現

類Proxy

生成代理的具體的操做類,能夠爲一個or多個接口動態的實現代理類

缺點 就是被代理的類必須是接口的實現類(依賴於接口),

若是某些類沒有實現接口 則不能用jdk代理

 1 package Proxy.DynamicProxy.JDKProxy;
 2 
 3 /**
 4  * 目標接口
 5  */
 6 public interface UserManager {
 7 
 8     public void addUser(String name ,String password);
 9     public void detUser(String name);
10 }
 1 package Proxy.DynamicProxy.JDKProxy;
 2 
 3 public class UserManagerImpl implements UserManager {
 4     @Override
 5     public void addUser(String id, String password) {
 6         System.out.println("調用了UserManagerImpl.addUser()方法");
 7     }
 8 
 9     @Override
10     public void detUser(String id) {
11         System.out.println("調用了UserManagerImpl.detUser()的方法");
12     }
13 }
 1 package Proxy.DynamicProxy.JDKProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 /**
 8  * JDK動態代理類
 9  */
10 public class JDKDynamicProxy implements InvocationHandler {
11     //須要代理的目標對象
12     private Object targetObject;
13 
14     public Object newProxy(Object targetObject) {
15         //將目標對象傳入進行代理
16         this.targetObject = targetObject;
17         //將代理對象返回 //其中有三個參數
18         return Proxy.newProxyInstance(
19                 targetObject.getClass().getClassLoader(),
20                 targetObject.getClass().getInterfaces(),
21                 this);
22     }
23 
24     // invoke 測試方法
25     @Override
26     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
27 
28         // 代理前 :邏輯處理的方法(函數)
29         checkPopedom();
30         Object reflect = null;
31         // 調用invoke()
32         reflect = method.invoke(targetObject, args);
33         // 代理後:
34         isOK();
35         return reflect;
36     }
37 
38     private void isOK() {
39         System.out.println("權限經過:isOK()");
40     }
41 
42     private void checkPopedom() {
43         System.out.println("檢查權限:checkPopedom()");
44     }
45 
46 }
 1 package Proxy.DynamicProxy.JDKProxy;
 2 
 3 /**
 4  * 測試類
 5  *
 6  */
 7 public class JDKDynamicProxyTest {
 8     public static void main(String[] args) {
 9 
10         JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy();
11         //JDK動態代理對象傳入一個須要代理的對象 而後用須要代理的對象接收就OK啦
12         UserManager userManagerJDK = (UserManager) jdkDynamicProxy.newProxy(new UserManagerImpl());
13         userManagerJDK.addUser("tom","root");
14         userManagerJDK.addUser("jeck","root");
15         /**
16          * 運行結果:
17          * 檢查權限:checkPopedom()
18          * 調用了UserManagerImpl.addUser方法
19          * 權限經過:isOK()
20          * 檢查權限:checkPopedom()
21          * 調用了UserManagerImpl.addUser方法
22          * 權限經過:isOK()
23          */
24     }
25 }

 

cglib

原理是針對target類 生成一個子類 覆蓋方法實現加強

缺點 基於繼承 沒法代理final類(final類沒法被繼承,如String)

須要的jar包 :asm-3.3.1,cglib-2.2.jar ps:jar包版本不一樣可能會報錯         

詳細狀況請看:www.cnblogs.com/cruze/p/3865180.html#lable1

參看文獻:

https://shifulong.iteye.com/blog/2166770

https://www.cnblogs.com/gonjan-blog/p/6685611.html

http://blog.jobbole.com/104433/

https://baike.baidu.com/item/動態代理類/5087985?fr=aladdin

相關文章
相關標籤/搜索