代理是一種經常使用的設計模式,其目的就是爲其餘對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。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 代理主要用到了
接口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 }
原理是針對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