需要掌握的程度:
1. 什么是JDK動態代理 ?
使用jdk的反射機制,創建物件的能力(創建的是代理類的物件),而不用創建類檔案,不用寫java檔案,
- 動態:在程式執行時,呼叫jdk提供的方法才能創建代理類的物件,
- jdk動態代理,必須有介面,目標類必須實作介面, 沒有介面時,需要使用cglib動態代理,
2. 知道動態代理能做什么?
可以在不改變原來目標方法功能的前提下, 可以在代理中增強自己的功能代碼,
代理模式:
1.代理:代購, 中介,換ip,商家等等,
- 比如有一家美國的大學, 可以對全世界招生,
- 留學中介(代理): 幫助這家美國的學校招生, 中介是學校的代理, 中介是代替學校完成招生功能,
為什么要找中介 ?
- 中介是專業的, 方便,
- 家長現在不能自己去找學校, 家長沒有能力訪問學校, 或者美國學校不接收個人來訪,
買東西都是商家賣, 商家是某個商品的代理, 你個人買東西, 肯定不會讓你接觸到廠家的,
2. 在開發中也會有這樣的情況:
- a類, 本來要呼叫c類的方法, 完成某個功能,但是c不讓a呼叫,
解決方案:
- 在 a 和 c 直接 創建一個 b 代理, c 讓 b訪問,
a --- 訪問b --- 訪問c
3.使用代理模式的作用
- 功能增強: 在你原有的功能上,增加了額外的功能,
- 控制訪問: 代理類不讓你訪問目標,例如商家不讓用戶訪問廠家,
靜態代理 :
- 代理類是自己手動實作的,自己創建一個java類,表示代理類;同時你所要代理的目標類是確定的,
優點: 實作簡單;容易理解,
缺點:當你的專案中,目標類和代理類很多的時候:
1)當目標類增加了, 代理類可能也需要成倍的增加,代理類數量過多,
2)當你的介面中功能增加了, 或者修改了,會影響眾多的實作類,廠家類,代理類都需要修改,影響比較多,
動態代理:
- 在程式執行程序中,使用jdk的反射機制,創建代理類物件, 并動態的指定要代理目標類;換句話說: 動態代理是一種創建java物件的能力,讓你不用創建代理類,就能創建代理類物件,
優點:
1)代理類數量可以很少,
2)當你修改了介面中的方法時,不會影響代理類,
動態代理的實作:
- jdk 動態代理(理解):使用 java 反射包中的類和介面(InvocationHandler , Method, Proxy)實作動態代理的功能,
- cglib動態代理(了解): cglib是第三方的工具庫,cglib的原理是繼承, cglib通過繼承目標類,創建它的子類,在子類中重寫父類中同名的方法, 實作功能的修改,
由于cglib是繼承,重寫方法,所以要求目標類不能是final的, 方法也不能是final的,
cglib的要求目標類比較寬松, 只要能繼承就可以了,cglib在很多的框架中使用,比如 mybatis ,spring框架中都有使用,
jdk 動態代理實作步驟:
1、創建介面,定義目標類要完成的功能:
//目標介面
public interface UsbSell {
float sell(int amount);
}
2、創建目標類實作介面:
//目標類
public class UsbKingFactory implements UsbSell {
@Override
//目標方法
public float sell(int amount) {
//廠家賣85.6元
return 85.6f;
}
}
3、創建InvocationHandler介面的實作類,在invoke方法中完成代理類的功能:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//必須實作InvocationHandler介面,完成代理類要做的功能(1.呼叫目標方法,2.功能增強)
public class MySellHandler implements InvocationHandler {
private Object target = null;
//動態代理:目標物件是活動的,不是固定的,需要傳入進來,傳入是誰,就給誰創建代理,
public MySellHandler(Object target) {
//給目標物件賦值
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//儲存方法執行結果
Object res = null;
//執行目標方法
res = method.invoke(target,args);
//商家需要加價(功能增強)
if( res != null ){
Float price = (Float)res;
price = price + 25;
res = price;
}
//再送你一張優惠券(功能增強)
System.out.println("謝謝惠顧,送您一張優惠券,親!");
//增加的價格
return res;
}
}
4、使用Proxy類的靜態方法,創建代理物件, 并把回傳值轉為介面型別:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class MainShop {
public static void main(String[] args) {
//1. 創建目標物件
UsbSell factory = new UsbKingFactory();
//2.創建InvocationHandler物件
InvocationHandler handler = new MySellHandler(factory);
//3.創建代理物件
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler);
//4.通過代理執行方法
float price = proxy.sell(1);
System.out.println("通過動態代理物件,呼叫方法獲得的結果:"+price);
}
}
JDK動態代理執行流程 :

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/458607.html
標籤:Java
上一篇:Spring 原始碼(3)Spring BeanFactory 是怎么創建的?
下一篇:執行緒池
