1. 程式人生 > 程式設計 >Java基礎之代理原理與用法詳解

Java基礎之代理原理與用法詳解

本文例項講述了Java基礎之代理原理與用法。分享給大家供大家參考,具體如下:

1.什麼是代理

動態代理技術是整個java技術中最重要的一個技術,它是學習java框架的基礎,不會動態代理技術,那麼在學習Spring這些框架時是學不明白的。

  動態代理技術就是用來產生一個物件的代理物件的。在開發中為什麼需要為一個物件產生代理物件呢?
  舉一個現實生活中的例子:歌星或者明星都有一個自己的經紀人,這個經紀人就是他們的代理人,當我們需要找明星表演時,不能直接找到該明星,只能是找明星的代理人。比如劉德華在現實生活中非常有名,會唱歌,會跳舞,會拍戲,劉德華在沒有出名之前,我們可以直接找他唱歌,跳舞,拍戲,劉德華出名之後,他乾的第一件事就是找一個經紀人,這個經紀人就是劉德華的代理人(代理),當我們需要找劉德華表演時,不能直接找到劉德華了(劉德華說,你找我代理人商談具體事宜吧!),只能是找劉德華的代理人,因此劉德華這個代理人存在的價值就是攔截我們對劉德華的直接訪問!

  這個現實中的例子和我們在開發中是一樣的,我們在開發中之所以要產生一個物件的代理物件,主要用於攔截對真實業務物件的訪問。那麼代理物件應該具有什麼方法呢?代理物件應該具有和目標物件相同的方法

  所以在這裡明確代理物件的兩個概念:
    1、代理物件存在的價值主要用於攔截對真實業務物件的訪問。
    2、代理物件應該具有和目標物件(真實業務物件)相同的方法。劉德華(真實業務物件)會唱歌,會跳舞,會拍戲,我們現在不能直接找他唱歌,跳舞,拍戲了,只能找他的代理人(代理物件)唱歌,跳舞,拍戲,一個人要想成為劉德華的代理人,那麼他必須具有和劉德華一樣的行為(會唱歌,會跳舞,會拍戲),劉德華有什麼方法,他(代理人)就要有什麼方法,我們找劉德華的代理人唱歌,跳舞,拍戲,但是代理人不是真的懂得唱歌,跳舞,拍戲的,真正懂得唱歌,跳舞,拍戲的是劉德華,在現實中的例子就是我們要找劉德華唱歌,跳舞,拍戲,那麼只能先找他的經紀人,交錢給他的經紀人,然後經紀人再讓劉德華去唱歌,跳舞,拍戲。

2.代理的分類

靜態代理:代理類和委託類在程式碼執行之前關係就已經確定了,也就是說在代理類的程式碼一開始就已經存在了。

動態代理:動態代理類的位元組碼在程式執行的時候生成。

3.Java中的代理

"java.lang.reflect.Proxy"類介紹

現在要生成某一個物件的代理物件,這個代理物件通常也要編寫一個類來生成,所以首先要編寫用於生成代理物件的類。在java中如何用程式去生成一個物件的代理物件呢,java在JDK1.5之後提供了一個"java.lang.reflect.Proxy"類,通過"Proxy"類提供的一個newProxyInstance方法用來建立一個物件的代理物件,如下所示:

static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

newProxyInstance方法用來返回一個代理物件,這個方法總共有3個引數,ClassLoader loader用來指明生成代理物件使用哪個類裝載器,Class<?>[] interfaces用來指明生成哪個物件的代理物件,通過介面指定,InvocationHandler h用來指明產生的這個代理物件要做什麼事情。所以我們只需要呼叫newProxyInstance方法就可以得到某一個物件的代理物件了。

編寫生成代理物件的類

在java中規定,要想產生一個物件的代理物件,那麼這個物件必須要有一個介面,所以我們第一步就是設計這個物件的介面,在介面中定義這個物件所具有的行為(方法)

StduentInterface.java--定義物件的行為介面

public interface StduentInterface {
 public int insertStudent(Student student);
}

StudentDao.java--定義目標業務物件類

public class StudentDAO implements StduentInterface {
 @Override
 public int insertStudent(Student student) {
  // 以下這段程式碼是業務邏輯
  return null == student ? 0 : 1;
 }
}

建立靜態代理

public class StudentStaticProxyDAO {
 private StudentDAO studentDAO;
 public StudentStaticProxyDAO(StudentDAO studentDAO) {
  this.studentDAO = studentDAO;
 }
 public int insertStudent(Student student) {
  Logger.info("開始插入一個學生記錄: " + student.toString());
  int number = studentDAO.insertStudent(student);
  Logger.info("插入 " + number + " 條學生記錄");
  return number;
 }
}

動態代理

public class LoggerDynamicProxy implements InvocationHandler{
 private Object target;
 public LoggerDynamicProxy(Object obj) {
  this.target = obj;
 }
 /**
  * 動態代理類中的 invoke 方法
  *
  * 三個引數的意義:
  *
  * proxy :代理物件
  * method : 委託類中要呼叫的方法
  * args :method 方法的引數
  */
 @Override
 public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
  Logger.info("before 業務方法呼叫之前");
  Object obj = method.invoke(target,args);
  Logger.info("before 業務方法呼叫之前");
  return obj;
 }
}

測試類

public class ProxyTest {
 public static void main(String[] args) {
  /**
   * 基礎元件準備
   */
  StudentDAO studentDao = new StudentDAO();
  Student student = new Student(100000);
  StudentStaticProxyDAO studentProxyDAO = new StudentStaticProxyDAO(studentDao);
  /**
   * 測試委託類的功能
   */
  System.out.println(studentDao.insertStudent(student));
  /**
   * 測試靜態代理類的功能
   */
  System.out.println(studentProxyDAO.insertStudent(student));
  /**
   * 測試動態代理類的功能
   */
  StduentInterface newProxyInstance = (StduentInterface)Proxy.newProxyInstance(studentDao.getClass().getClassLoader(),studentDao.getClass().getInterfaces(),new LoggerDynamicProxy(studentDao));
  int insertStudent = newProxyInstance.insertStudent(student);
  System.out.println(insertStudent);
}

執行結果

1
INFO: 開始插入一個學生記錄: Student [id=100000,name=null]
INFO: 插入 1 條學生記錄
1
INFO: before 業務方法呼叫之前
INFO: before 業務方法呼叫之前
1
INFO: before 業務方法呼叫之前
INFO: before 業務方法呼叫之前
1

更多java相關內容感興趣的讀者可檢視本站專題:《Java面向物件程式設計入門與進階教程》、《Java資料結構與演算法教程》、《Java操作DOM節點技巧總結》、《Java檔案與目錄操作技巧彙總》和《Java快取操作技巧彙總》

希望本文所述對大家java程式設計有所幫助。