Java-JDK動態代理(AOP)使用及實現原理分析

刺客伍六七發表於2020-10-13

Java-JDK動態代理(AOP)使用及實現原理分析

第一章:代理的介紹

介紹:我們需要掌握的程度

動態代理(理解) 基於反射機制

掌握的程度:

1.什麼是動態代理?

2.動態代理能夠做什麼?

後面我們在用Spirng和Mybatis的時候,要理解怎麼使用的.

1.什麼是代理?

代理,在我們日常生活之中就有體現,代購,中介,換ip,商家等等.

比如有一家美國的大學,可以對全世界招生.留學中介(代理 )

留學中介(代理):幫助這家美國的學校招生,中介是學校的代理中介是代替學校完成招生功能
代理特點

  1. 中介和代理他們要做的事情是一致的:招生
  2. 中介是學校代理,學校是目標
  3. 家長-------->中介(學校介紹,辦理入學手續)---------->美國學校
  4. 中介是代理,收取費用

2.為什麼要找中介

為什麼要找中介?
1.中介是專業的,方便.
2.家長現在不能自己去找學校。家長沒有能力訪問學校.或者美國學校不接收個人來訪

買東西都是商家賣, 商家是某個商品的代理, 你個人買東西,肯定不會讓你接觸到廠家的.

第二章:靜態代理

2.1 使用代理模式的作用

  1. 功能增強:在你原有的功能上,增加了額外的功能.新增加的功能,叫做功能增強
  2. 控制訪問:代理類不讓你訪問目標,例如商家不讓使用者訪問廠家

2.2 實現代理的方式

1.靜態代理:

1)代理類是自己手工實現的,自己建立一個java類,表示代理類

2)同時你所要代理的目標

特點:1)實現簡單2)容易理解。
模擬一個使用者購買u盤的行為。
使用者是客戶端類
商家:代理,代理某個品牌的u盤。
廠家:目標類。
三者的關係:使用者(客戶端)-—-商家(代理)-—-廠家(目標)
商家和廠家都是賣u盤的,他們完成的功能是一致的,都是賣u盤。

實現步驟:

實現步驟
1.建立一個介面,定義賣u盤的方法,表示你的廠家和商家做的事情
2.建立廠家類,實現1步驟的介面
3.建立商家,就是代理,也需要實現1步驟中的介面
4.建立客戶端類,呼叫商家的方法買一個u盤

2.3 具體實現

實現步驟
1.建立一個介面,定義賣u盤的方法,表示你的廠家和商家做的事情

package com.rango.service;
public interface usbSell {
    /**
     * 定義一個方法 引數 amount:表示一次購買的數量,暫時不用
     * 返回值表示一個u盤的價格
     * @param amount
     * @return
     */
    float sell(int amount);
}

2.建立廠家類,實現1步驟的介面

package com.rango.factory;

import com.rango.service.usbSell;
//目標類:金士頓廠家,不接受使用者的單獨購買
public class UsbKingFactory implements usbSell {
    /**
     * 定義一個方法 引數 amount:表示一次購買的數量,暫時不用
     * 返回值表示一個u盤的價格
     *
     * @param amount
     * @return
     */
    @Override
//一個128G的U盤是85元.
//    後期根據amount,可以實現不同的價格,例如10000個,單擊是80,50000個75
    public float sell(int amount) {
        return 85.0f*amount;
    }
}

3.建立商家,就是代理,也需要實現1步驟中的介面

package com.rango.business;

import com.rango.factory.UsbKingFactory;
import com.rango.service.usbSell;


//淘寶是一個商家,代理金士頓U盤的銷售
public class TaoBao implements usbSell {
//      宣告 商家代理的廠家具體是誰
    private UsbKingFactory factory =new UsbKingFactory();

    @Override
//    實現銷售U盤功能
    public float sell(int amount) {
//        向廠家傳送訂單,告訴廠家,我買了U盤,廠家發貨
//        傳送給工廠,我需要的訂單,返回報價
        float price = factory.sell(amount);
//        商家需要加價也就是代理要增加價格
        price = price + 25;
//在目標類的方法呼叫後,你做的其他功能,都是增強的意思
        System.out.println("淘寶再給你返回一個優惠券,或者紅包");
//        增加的價格
        return price;
    }
}

4.建立客戶端類,呼叫商家的方法買一個u盤

import com.rango.business.TaoBao;

public class shopMain {
    public static void main(String[] args){
//             建立代理的商家淘寶物件
        TaoBao taoBao = new TaoBao();
//        我只向淘寶買一件產品,得到報價
        float price = taoBao.sell(2);
        System.out.println("購買一件產品.淘寶的報價為: "+price);
    }
}

所以我們再次總結代理類完成的功能:

  1. 目標類中方法的呼叫
  2. 功能增強

所屬我們只有一個代理商,我們實際上可以寫多個代理商,

2.4 靜態代理的優缺點

我們再次總結一下靜態代理的優缺點

優點:

  1. 實現簡單
  2. 容易簡單

確定:當你的專案中,目標類的代理類很多的時候,有一下的缺點

  1. 當目標類增加了,代理類可能也需要成倍的增加
  2. 當你的介面中功能在增加了,或者修改了,會影響眾多的實現類,廠家類,代理都需要修改,影響比較多.

所以我們繼續學習動態代理

第三章 動態代理

本章,我們所掌握的是

1)什麼是動態代理?

​ 使用jdk的反射機制,建立物件的能力,建立的是代理類的的物件.而不用我們建立類檔案,不用寫java檔案, 什麼叫動態?在程式執行時,呼叫jdk提供的方法才能建立代理類的物件

2)知道動態代理能做什麼?

2.1 靜態代理和動態代理模式的對比

在靜態代理中目標很多的時候,可以使用動態代理,避免靜態代理的缺點

在靜態代理中目標類很多時候,可以使用動態代理,避免靜態代理的缺點。
動態代理中目標類即使很多,

  1. 代理類數量可以很少,

  2. 當你修改了介面中的方法時,不會影響代理類。

動態代理:在程式執行過程中,使用jdk的反射機制,建立代理類物件,並動態的指定要代理目標類。
換句話說:動態代理是一種建立java象的能力,讓你不用建立 TaoBao類就能建立代理類物件,除去了中間商

在java中,要想建立物件

  1. 建立類檔案,java 檔案編譯為class
  2. 使用構造方法,建立類的物件

2.1 動態代理的介紹

  1. 動態代理是指代理類物件在程式執行時由JVM根據反射機制動態生成的。動態代理不需要定義代理類的,java原始檔。
  2. 動態代理其實就是jdk執行期間,動態建立class位元組碼並載入到JVM。
  3. 動態代理的實現方式常用的有兩種:使用JDK代理,與通過CGLlB動態代理。

動態代理的實現:

  1. jdk動態代理(理解):使用java反射包中的類和介面實現動態代理的功能,反射包java.lang.reflect,裡面有三個類:InvocationHandler,Method,Proxy
  2. cglib動態代理(瞭解): cglib是第三方的工具庫,建立代理物件
    1. cglib的原理是繼承,cglib通過繼承目標類,建立它的子類,在子類中
      重寫父類中同名的方法,實現功能的修改。
    2. 因為cglib是繼承,重寫方法,所以要求目標類不能是fina1的,方法也不能是final的。cglib的要求目標類比較寬鬆,只要能繼承就可以了。cglib在很多的框架中使用,
      比如mybatis,spring框架中都有使用。
package Test;

import com.rango.Impl.HelloServiceImpl;
import com.rango.service.HelloService;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestApp {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        HelloService service = new HelloServiceImpl();
//        service.sayhello("張三");
//        以上是常規方法執行sayhello
//        下面我們使用反射機制進行建立sayhello方法,核心Method(類中的方法)
        HelloServiceImpl target = new HelloServiceImpl();
//        獲取sayhello名稱對應的Method類物件
//         public Method getM   ethod(String name, Class<?>... parameterTypes)
//        加入,該方法的引數有多個該怎麼辦?
//        parameterTypes引數是一個類物件陣列,按宣告的順序標識方法的形式引數型別。
        Method method = HelloService.class.getMethod("sayhello", String.class);
//        通過Metho可以執行sayhello方法的呼叫
        /*
        *  public Object invoke(Object obj, Object... args)
        *       表示執行方法的呼叫
        *   引數:
        *       1.Object,表示物件,要執行這個物件的方法
        *       2.Object...args,方法執行時的引數值
        * 返回值:
        *       Object:方法執行後的返回值
        * */
        Object ret = method.invoke(target, "李四");
    }
}

2.2 回顧反射 Method類

Method類的結構圖

  • Class Method
    • java.lang.Object
      • java.lang.reflect.AccessibleObject
        • java.lang.reflect.Executable
          • java.lang.reflect.Method

2.2.1 class.getMethod

Method method = HelloService.class.getMethod("sayhello", String.class,Integer.class);

提出問題?

    public Method getMethod(String name, Class<?>... parameterTypes)

加入,該方法的引數有多個該怎麼辦?
parameterTypes引數是一個類物件陣列,按宣告的順序標識方法的形式引數型別。

2.2.2 Method.invoke

public Object invoke(Object obj,Object... args)

*  public Object invoke(Object obj, Object... args)
*       表示執行方法的呼叫
*   引數:
*       1.Object,表示物件,要執行這個物件的方法
*       2.Object...args,方法執行時的引數值
* 返回值:
*       Object:方法執行後的返回值
* 

2.3 JDK動態代理

相關文章