對java 中動態代理和靜態代理的理解

代理模式能夠有效的將具體實現與調用進行解耦,經過面向接口進行編碼徹底將具體的實現隱藏在內部。html

代理實現的通常模式:定義一個接口,而後建立具體的實現類實現這個接口,建立一個代理類還實現這個接口,具體的實現類須要把接口中定義的方法的業務邏輯實現,而代理類中的方法只要調用實現類中的對應方法便可。以後咱們須要使用接口中的某個方法的功能時直接調用代理類的方法就能夠了,將具體的實現類隱藏在底層。ide

靜態代理和動態代理的區別:主要是代理類的建立不一樣。靜態代理是咱們在編譯以前就直接實現與代理類相同的接口,直接在實現的方法中調用實現類的相應方法就能夠了。而動態代理不一樣,咱們不知道何時建立,建立針對哪一個接口,實現類的代理類等。靜態代理能夠直接編碼建立,而動態代理是經過反射機制來抽象出代理類的建立過程。函數

所謂靜態代理就是,在編譯的時候就將接口、實現類、代理類都手動完成。測試

接口:this

/**
 * 代理類和被代理類公共的接口
 * @author TYX
 *
 */
public interface Person {
   //上交班費
   void getMoney();

}

具體實現類:編碼

/**
 * 定義一個被代理的類,繼承公共接口
 * @author TYX
 *
 */
public class Student implements Person {

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

   @Override
   public void getMoney() {
      System.out.println("上交班費50元");

   }

}

代理類:spa

/**
 * 靜態代理在程序運行以前已經編譯好了。
 * 代理類,類中定義一個被代理類的實體,還有代理的行爲
 * @author TYX
 *
 */
public class StudentProxy implements Person {

   //定義一個被代理類的對象
   Student student;
   
   //這個構造器傳入的是一個接口的對象
   public StudentProxy(Person student2) {
      //只代理student這個類
      if(student2.getClass() == Student.class){
         this.student = (Student) student2;
      }
   }

   //代理上交班費
   @Override
   public void getMoney() {
      /*代理類就是在訪問實際對象時引入的必定程度的間接性,正是因爲這種間接性,能夠附加不少種
      用途間接性就是指不直接調用對象的方法,那麼咱們在代理過程當中加上一些其餘的用途,使用用代理就能夠輕鬆辦到   * */    
      System.out.println("最近這位同窗表現很好哦~");//在一個切點以前能執行一些別的操做這就是AOP中的特色。也能夠在調用代理類以後進行操做。
      student.getMoney();

   }

}

測試類:代理

public class TestStaticProxy {

   public static void main(String[] args) {
      //定義一個學生對象
      Person student = new Student("張三");
      //生成代理對象,並將學生對象傳給代理對象
      Person moniter = new StudentProxy(student);
      //班長代理上交班費
      moniter.getMoney();
   }
}

結果htm

最近這位同窗表現很好哦~
上交班費50元對象

動態代理:代理類在運行時因需實時建立。

接口:

public interface Person {
   //上交班費
   void getMoney();

}

具體實現類

/**
 * 定義一個被代理的類,繼承公共接口
 * @author TYX
 *
 */
public class Student implements Person {

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

   //定義一個方法執行時間的方法
   @Override
   public void getMoney() {
      try {
         Thread.sleep(1000);
      } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      System.out.println("上交班費50元");

   }

}

代理類

/**
 * 動態代理實現
 * 類中有一個被代理類的實例,全部執行代理對象的方法都會被替換成執行invock方法
 * @author TYX
 *
 */
public class StudentProxyHandler<T> implements InvocationHandler {
   //定義一個被代理類的對象
   private T targe;
   
   public StudentProxyHandler(T targe) {
      super();
      this.targe = targe;
   }

   /**
    * proxy 是被代理對象(實例)
    * method 正在執行的方法
    * args 調用目標方法時傳入的實參
    */
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("代理執行" + method.getName() + "方法");
      MonitorUtil.start();
      Object result = method.invoke(targe, args);
      MonitorUtil.finish(method.getName());
      return result;
   }
   
   public Object proxyInstance(){
      return Proxy.newProxyInstance(targe.getClass().getClassLoader(), targe.getClass().getInterfaces(), this);
   }

}

測試類

/**
 * 建立一個動態代理對象的步驟
 * 1. 建立一個與代理對象向關聯的invocationHandler
      InvocationHandler stuHandler = new StudentProxyHandler<Person>(student1);
   2. 使用Proxy類的getProxyClass靜態方法生成一個動態代理類的stuProxyClass
      Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class.getInterfaces());
   3. 得到stuProxyClass 中一個帶InvocationHandler參數的構造器cnstructor
      Constructor<?> constructor = stuProxyClass.getConstructor(InvocationHandler.class);
   4. 構造器Constructor來建立一個動態實例
      Person stuProxy = (Person) constructor.newInstance(stuHandler);
 * @author TYX
 *
 */
public class TestDynamicProxy {

   public static void main(String[] args) throws NoSuchMethodException, SecurityException {
//    Person student = new Student("張三");
      //建立一個被代理類的實例對象
      Person student1 = new Student1("李四");
      //建立一個與代理對象向關聯的invocationHandler
      InvocationHandler stuHandler = new StudentProxyHandler<Person>(student1);
      //建立一個代理對象stuProxy來代理被代理類的實例,代理對象的每一個執行方法都會替換執行invocation中的invock方法
      Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
      //代理執行上交班費的方法
      stuProxy.getMoney();
      
      /*Person student1 = new Student1("李四");
      //建立一個與代理對象向關聯的invocationHandler
      StudentProxyHandler stuHandler = new StudentProxyHandler<Person>(student1);
      //建立一個代理對象stuProxy來代理被代理類的實例,代理對象的每一個執行方法都會替換執行invocation中的invock方法
      Person stuProxy = (Person) stuHandler.proxyInstance();
      //代理執行上交班費的方法
      stuProxy.getMoney();*/
   }
}

結果

代理執行getMoney方法
交做業嘍
getMoney方法耗時2000ms

總結:

1.首先要建立接口,jdk代理是基於接口實現的。

2.建立一個有代理對象關聯的invocationHandler,重寫invocationHandler 接口裏的invock()方法

3.經過Proxy.newProxyInstance建立一個代理對象。

4.用代理對象調用方法

接下來看一下cglib動態代理的實現:https://www.cnblogs.com/mr-long/p/5889054.html

jdk動態代理須要實現接口,當須要代理的類沒有實現接口時cglib代理是一個很好的選擇。可是被代理類中的final方法,沒法進行代理,由於子類中沒法重寫final函數

相關文章
相關標籤/搜索