JAVA關於靜態代理和JDK動態代理

關於靜態代理和JDK動態代理

什麼是代理

代理通俗來說就是代替某人去做一件事情,可以舉個例子,假設有個老師今天生病了不能來上課,那麼是不是可以請一個代理老師來幫上課,實際意義上來說這兩個老師完成的東西是一樣的,都是給學生傳道受業解惑,但是,代理老師是不是能在原來上課的基礎上拓展更多“功能”,比如說代理老師去上課之前,先到隔壁班看了一眼中意的女老師有沒有來,上完課之後又去吃了自己最愛喫的螺螄粉~看到這兒有沒有感覺到跟一個東西很像,所以SpringAOP面向切面變成的原理就是這樣,當然實際實現方面會更加複雜。

代理分爲三個角色

  1. 接口
  2. 委託類
  3. 代理類

靜態代理

我們先說一下靜態代理,就用我們前面舉的例子,直接上代碼。

接口:

package com.staticproxy;

//我和代理老師都是老師,共同實現了老師接口
public interface Teacher {
   void teach();
}

委託類:

package com.staticproxy;
//這個就是生病的老師
public class MathTeacher implements Teacher {
   @Override
   public void teach() {
       System.out.println("傳道受業解惑40分鐘");
   }
}

代理類:

package com.staticproxy;
//這個是代理老師
public class ProxyTeacher implements Teacher {
   //通過構造器注入被代理對象(注入一個生病老師的對象)
   private Teacher targetTeacher;
   public ProxyTeacher(Teacher teacher){
       this.targetTeacher=teacher;
   }

   //代理老師實現了接口也有teach方法
   @Override
   public void teach() {
       System.out.println("上課之前先去隔壁班看美女老師");
       //調用生病老師的teach方法
       targetTeacher.teach();
       System.out.println("上完課了,去喫個螺螄粉壓壓驚!");
   }
}

Client的main方法:

package com.staticproxy;

public class Client {
   public static void main(String[] args) {
       Teacher teacher=new MathTeacher();
       Teacher proxyteacher=new ProxyTeacher(teacher);
       proxyteacher.teach();
   }
}

結果:
在這裏插入圖片描述
靜態代理跟着走一遍應該很快就能理清,非常簡單。
下面我們繼續動態代理,動態代理需要用到反射機制。

JDK動態代理

接口:

package com.jdkproxy;

public interface Teacher {
   void teach();
}

沒什麼好說的跟前面一樣的接口

委託類:

package com.jdkproxy;

public class MathTeacher implements Teacher {
   @Override
   public void teach() {
       System.out.println("傳道受業解惑40分鐘");
   }
}

重點來了

package com.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 注意動態代理這裏不需要再實現教師接口了
* 這樣才能體現動態的概念,往往在實際應用之中
* 我們是不會提前知道我們需要代理什麼對象的
*/
public class ProxyTeacher {

   private Object targetteacher;
   public ProxyTeacher(Teacher teacher){
       this.targetteacher=teacher;
   }

/**
* 這裏調用了Proxy的newProxyInstance方法獲得代理對象
* 參數1表示被代理對象的類加載器
* 參數2是被代理對象實現的接口,可以是數組(表示實現多個接口)
* 參數3是用匿名內部類實例化一個實現了InvocationHandler接口的對象
*/
   public Object getProxyInstance(){
       return Proxy.newProxyInstance(targetteacher.getClass().getClassLoader(), targetteacher.getClass().getInterfaces(),
               new InvocationHandler() {
                   /**
                   * @param proxy 調用這個方法的代理實例
    			   * @param method 要調用的方法
    			   * @param args 方法調用時所需要的參數
    			   * @return 方法調用的結果
   				   */
   				   @Override
                   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       System.out.println("上課之前先去隔壁班看美女老師");
                       method.invoke(targetteacher,args);
                       System.out.println("上完課了,去喫個螺螄粉壓壓驚");
                       return null;
                   }
               });
   }
}

Client:

package com.jdkproxy;

public class Client {
   public static void main(String[] args) {
       Teacher teacher=new MathTeacher();
       Teacher proxyTeacher=(Teacher)new ProxyTeacher(teacher).getProxyInstance();
       proxyTeacher.teach();
   }
}

結果:
在這裏插入圖片描述
總結:
當然SpringAop用的動態代理更爲複雜,還有cglib動態代理等其他技術這裏不做延伸,我們只需要知道,動態代理可以在完成原來對象實現的功能的基礎之上,繼續延伸和拓展,這也是SpringAop面向切面編程的一個重要思想,廣泛應用在比如日誌,異常處理,監控,事務管理等功能上。這就是面向切面的大致原理,可以這麼想,上課本來就是老師必做的流程,在該流程上橫向切入了看美女和喫東西兩個功能,而絲毫不影響功能的實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章