保護代理的實現(xiàn)方式有兩種:靜態(tài)代理和動態(tài)代理。首先代理模式的作用是什么呢?控制訪問。
代理模式
場景
為其他對象提供一種代理,控制對這個對象的訪問——控制訪問條件(特點)
1、代理對象和被代理對象繼承同一個父類
2、代理對象持有被代理對象的引用為什么要滿足這個條件
當然是做控制訪問,代理類和被代理類繼承或?qū)崿F(xiàn)同一個接口,實際操作的還是被代理類,代理類只是做訪問控制
虛代理
- 根據(jù)需要創(chuàng)建開銷很大的對象,該對象只有在需要的時候才會被真正創(chuàng)建
- 懶加載 LazyLoad,ORM(對象映射關(guān)系框架)
靜態(tài)代理
首先引用一個案例:
代理模式條件首先是代理對象和被代理對象要繼承或?qū)崿F(xiàn)同一個接口,所以先定義一個接口 OrderApi
public interface OrderApi {
public String getUserName();
public void setUserName(String userName,String updateUser);
public String getOrderName();
public void setOrderName(String orderName,String updateUser);
public String getOrderId();
public void setOrderId(String orderId,String updateUser);
public String getOrderTime();
public void setOrderTime(String orderTime,String updateUser);
}
然后定義一個被代理類Order(實際做業(yè)務(wù)操作的類,以下以JavaBean做示范,并非說被代理類是JavaBean),然后實現(xiàn)OrderAPI接口
public class Order implements OrderApi {
private String userName;
private String orderName;
private String orderId;
private String orderTime;
public Order(String userName, String orderName, String orderId, String orderTime) {
super();
this.userName = userName;
this.orderName = orderName;
this.orderId = orderId;
this.orderTime = orderTime;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName,String updateUser) {
this.userName = userName;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName,String updateUser) {
this.orderName = orderName;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId,String updateUser) {
this.orderId = orderId;
}
public String getOrderTime() {
return orderTime;
}
public void setOrderTime(String orderTime,String updateUser) {
this.orderTime = orderTime;
}
}
然后定義一個代理類OrderProxy,實現(xiàn)OrderApi接口并持有Order被代理類引用,當進行set操作的時候做權(quán)限判斷,只有本人可以修改這個訂單:
public class OrderProxy implements OrderApi {
private Order order;
public OrderProxy(Order order) {
this.order = order;
}
@Override
public String getUserName() {
return order.getUserName();
}
@Override
public void setUserName(String userName, String updateUser) {
if (updateUser != null && updateUser.equals(order.getUserName())) {
order.setUserName(userName, updateUser);
} else {
throw new IllegalAccessError(updateUser + "同學(xué),你沒有權(quán)限操作!");
}
}
@Override
public String getOrderName() {
return order.getOrderName();
}
@Override
public void setOrderName(String orderName, String updateUser) {
if (updateUser != null && updateUser.equals(order.getUserName())) {
order.setOrderName(orderName, updateUser);
} else {
throw new IllegalAccessError(updateUser + "同學(xué),你沒有權(quán)限操作!");
}
}
@Override
public String getOrderId() {
return order.getOrderId();
}
@Override
public void setOrderId(String orderId, String updateUser) {
if (updateUser != null && updateUser.equals(order.getUserName())) {
order.setOrderId(orderId, updateUser);
} else {
throw new IllegalAccessError(updateUser + "同學(xué),你沒有權(quán)限操作!");
}
}
@Override
public String getOrderTime() {
return order.getOrderTime();
}
@Override
public void setOrderTime(String orderTime, String updateUser) {
if (updateUser != null && updateUser.equals(order.getUserName())) {
order.setOrderTime(orderTime, updateUser);
} else {
throw new IllegalAccessError(updateUser + "同學(xué),你沒有權(quán)限操作!");
}
}
}
最后寫一個測試類:
public class Client {
public static void main(String[] args) {
Order order = new Order("張三","Mac Pro 訂單","999999","2021/03/12");
OrderProxy orderProxy = new OrderProxy(order);
orderProxy.setOrderName("iPhone 12 Pro Max 訂單", "張三");
System.out.println("現(xiàn)在的訂單名稱為:"+orderProxy.getOrderName());
}
}
通過以上的一個案例會發(fā)現(xiàn)靜態(tài)代理有一個很大的確定,那就是做權(quán)限 保護判斷等邏輯的時候,代理類里的每個函數(shù)都需要手動判斷一次,特別繁瑣導(dǎo)致一堆垃圾代碼,而且如果目標接口發(fā)生改變,被代理類對應(yīng)的函數(shù)也需要改一遍很麻煩,這時候就引入了一個動態(tài)代理:
動態(tài)代理
- 不需要手動創(chuàng)建代理對象,而是由JVM自動幫我們創(chuàng)建,而且代理對象自動實現(xiàn)了目標接口
-
他是通過動態(tài)生成class字節(jié)碼做到的
image.png
具體是怎么做的呢?

自動生成的代理類對應(yīng)的每個函數(shù)會做這樣一個操作,將當前函數(shù)傳入到InvocationHandler實現(xiàn)類的invoke函數(shù)中,再在InvocationHandler 的 invoke函數(shù)中做統(tǒng)一權(quán)限等判斷操作最后調(diào)用被代理類對應(yīng)的函數(shù)
public class DynamicInvocationHandler implements InvocationHandler {
private Order order;
public void setTarget(Order order) {
this.order = order;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 所有被代理對象的方法被執(zhí)行,都會傳入到invoke方法中
// 方法名稱只要是set開頭,進行權(quán)限檢查
if (method.getName().startsWith("set")) {
if (order != null && order.getUserName() != null && order.getUserName().equals(args[1])) {
return method.invoke(order, args);
} else {
throw new IllegalAccessError("沒有操作權(quán)限!");
}
}
return method.invoke(order, args);
}
}
