java jdk動態代理與cglib動態代理

  1. 先來看看靜態代理
  2. User.java
  3. package com.dao;  
  4.   
  5. /** 
  6.  * 定義一個用戶接口 
  7.  *  
  8.  * @author Administrator 
  9.  *  
  10.  */  
  11. public interface User {  
  12.     // 說話方法  
  13.     public void say();  
  14.   
  15. }  
  16. UserImp1.java
  17. package com.imp
  18. public class UserImp1 implements User{
  19. @Override
  20. public void say(){
  21. System.out.println("Now,I am say....");
  22. }
  23. }

  24. UserProxy.java
  25. package com.imp
  26. public class UserProxy implements User{
  27. private UserImp1 userImp1;
  28. public UserProxy(UserImp1 userImp1){
  29. this.userImp1=userImp1;
  30. }
  31. @Override
  32. public void say(){
  33. System.out.println("說話以前。。。。");
  34.  userImp1.say();
  35. System.out.println("說話以後。。。。。");
  36. }
  37. }
  38. TestUser.java
  39. package com.test
  40. public class TestUser{
  41. public static void main(String[] args){
  42. UserImp1 userImp1=new UserImp1();
  43. UserProxy userProxy=new UserProxy(userImp1);
  44. userProxy.say();
  45. }
  46. }

觀察代碼咱們能夠發現每一個代理類只能爲一個接口服務,這樣一來程序開發中必然會產生過多的代理。並且,全部的代理操做除了所調用的方法不同以外,其餘的操做同樣的,則此時確定是重複代碼。解決這一問題最好的作法是能夠經過一個代理類完成所有的代理功能,那麼此時就必須使用動態代理來完成】 java

JDK動態代理包含一個類和一個接口: node

  1. InvocationHandler接口: 
  2. public interface InvocationHandler { 
  3. public Object invoke(Object proxy,Method method,Object[] args) throws 
  4. Throwable; 
  5. 參數說明: 
    Object proxy:指被代理的對象。 
    Method method:要調用的方法 
    Object[] args:方法調用時所須要的參數  程序員

    能夠將InvocationHandler接口的子類想象成一個代理的最終操做類,替換掉ProxySubject。  編程

    Proxy類: 
    Proxy類是專門完成代理的操做類,能夠經過此類爲一個或多個接口動態地生成實現類,此類提供了以下的操做方法: 
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
    InvocationHandler h) 
                                   throws IllegalArgumentException 
    參數說明: 
    ClassLoader loader:類加載器 
    Class<?>[] interfaces:獲得所有的接口 
    InvocationHandler h:獲得InvocationHandler接口的子類實例  ide

    Ps:類加載器 
    在Proxy類中的newProxyInstance()方法中須要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器; 
    Booststrap ClassLoader:此加載器採用C++編寫,通常開發中是看不到的; 
    Extendsion ClassLoader:用來進行擴展類的加載,通常對應的是jre\lib\ext目錄中的類; 
    AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器。  this

    動態代理 
    與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不只簡化了編程工做,並且提升了軟件系統的可擴展性,由於Java 反射機制能夠生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。  spa

    動態代理示例: 
  6. package net.battier.dao;   
  7. public interface BookFacade {  
  8.     public void addBook();  
  9. }  
  10. BookFacadeImpl.java 
  11. package net.battier.dao.impl;  
  12.   import net.battier.dao.BookFacade; 
  13.   public class BookFacadeImpl implements BookFacade { 
  14.        @Override 
  15.        public void addBook() {  
  16.          System.out.println("增長圖書方法。。。"); 
  17.         } 
  18. }  
  19. BookFacadeProxy.java 
    1. package net.battier.proxy;  
    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.  * @author student 
    11.  *  
    12.  */  
    13. public class BookFacadeProxy implements InvocationHandler {  
    14.     private Object target;  
    15.     /** 
    16.      * 綁定委託對象並返回一個代理類 
    17.      * @param target 
    18.      * @return  
    19.      */  
    20.     public Object bind(Object target) {  
    21.         this.target = target;  
    22.         //取得代理對象  
    23.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
    24.                 target.getClass().getInterfaces(), this);   //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)  
    25.     }  
    26.   
    27.     @Override  
    28.     /** 
    29.      * 調用方法 
    30.      */  
    31.     public Object invoke(Object proxy, Method method, Object[] args)  
    32.             throws Throwable {  
    33.         Object result=null;  
    34.         System.out.println("事物開始");  
    35.         //執行方法  
    36.         result=method.invoke(target, args);  
    37.         System.out.println("事物結束");  
    38.         return result;  
    39.     }  
    40.   
    41. }  
    3 TestProxy.java 
    1. package net.battier.test;  
    2.   
    3. import net.battier.dao.BookFacade;  
    4. import net.battier.dao.impl.BookFacadeImpl;  
    5. import net.battier.proxy.BookFacadeProxy;  
    6.   
    7. public class TestProxy {  
    8.   
    9.     public static void main(String[] args) {  
    10.         BookFacadeProxy proxy = new BookFacadeProxy();  
    11.         BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
    12.         bookProxy.addBook();  
    13.     }  
    14.   
    15. }  
    可是,JDK的動態代理依靠接口實現,若是有些類並無實現接口,則不能使用JDK代理,這就要使用cglib動態代理了。 
  20. Cglib動態代理 
    JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。 
    示例 
  21. 一、BookFacadeCglib.java 
    1. package net.battier.dao;  
    2.   
    3. public interface BookFacade {  
    4.     public void addBook();  

 BookCadeImpl1.java .net

  1. package net.battier.dao.impl;  
  2.   
  3. /** 
  4.  * 這個是沒有實現接口的實現類 
  5.  *  
  6.  * @author student 
  7.  *  
  8.  */  
  9. public class BookFacadeImpl1 {  
  10.     public void addBook() {  
  11.         System.out.println("增長圖書的普通方法...");  
  12.     }  
  13. }  
三、BookFacadeProxy.java 

  1. package net.battier.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * 使用cglib動態代理 
  11.  *  
  12.  * @author student 
  13.  *  
  14.  */  
  15. public class BookFacadeCglib implements MethodInterceptor {  
  16.     private Object target;  
  17.   
  18.     /** 
  19.      * 建立代理對象 
  20.      *  
  21.      * @param target 
  22.      * @return  
  23.      */  
  24.     public Object getInstance(Object target) {  
  25.         this.target = target;  
  26.         Enhancer enhancer = new Enhancer();  
  27.         enhancer.setSuperclass(this.target.getClass());  
  28.         // 回調方法  
  29.         enhancer.setCallback(this);  
  30.         // 建立代理對象  
  31.         return enhancer.create();  
  32.     }  
  33.   
  34.     @Override  
  35.     // 回調方法  
  36.     public Object intercept(Object obj, Method method, Object[] args,  
  37.             MethodProxy proxy) throws Throwable {  
  38.         System.out.println("事物開始");  
  39.         proxy.invokeSuper(obj, args);  
  40.         System.out.println("事物結束");  
  41.         return null;  
  42.   
  43.   
  44.     }  
  45.   
  46. }  
  47. 四、TestCglib.java 

  1. package net.battier.test;  
  2.   
  3. import net.battier.dao.impl.BookFacadeImpl1;  
  4. import net.battier.proxy.BookFacadeCglib;  
  5.   
  6. public class TestCglib {  
  7.       
  8.     public static void main(String[] args) {  
  9.         BookFacadeCglib cglib=new BookFacadeCglib();  
  10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
  11.         bookCglib.addBook();  
  12.     }  
  13. }  
固然, Cglib來實現動態代理必須引入cglib-nodep.jar包
相關文章
相關標籤/搜索