保护代理的实现方式有两种:静态代理和动态代理。首先代理模式的作用是什么呢?控制访问。
代理模式
-
场景
为其他对象提供一种代理,控制对这个对象的访问——控制访问 -
条件(特点)
1、代理对象和被代理对象继承同一个父类
2、代理对象持有被代理对象的引用 -
为什么要满足这个条件
当然是做控制访问,代理类和被代理类继承或实现同一个接口,实际操作的还是被代理类,代理类只是做访问控制
虚代理
- 根据需要创建开销很大的对象,该对象只有在需要的时候才会被真正创建
- 懒加载 LazyLoad,ORM(对象映射关系框架)
静态代理
首先引用一个案例:
代理模式条件首先是代理对象和被代理对象要继承或实现同一个接口,所以先定义一个接口 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(实际做业务操作的类,以下以JavaBean做示范,并非说被代理类是JavaBean),然后实现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,实现OrderApi接口并持有Order被代理类引用,当进行set操作的时候做权限判断,只有本人可以修改这个订单:
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 + "同学,你没有权限操作!");
}
}
@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 + "同学,你没有权限操作!");
}
}
@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 + "同学,你没有权限操作!");
}
}
@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 + "同学,你没有权限操作!");
}
}
}
最后写一个测试类:
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("现在的订单名称为:"+orderProxy.getOrderName());
}
}
通过以上的一个案例会发现静态代理有一个很大的确定,那就是做权限 保护判断等逻辑的时候,代理类里的每个函数都需要手动判断一次,特别繁琐导致一堆垃圾代码,而且如果目标接口发生改变,被代理类对应的函数也需要改一遍很麻烦,这时候就引入了一个动态代理:
动态代理
- 不需要手动创建代理对象,而是由JVM自动帮我们创建,而且代理对象自动实现了目标接口
-
他是通过动态生成class字节码做到的
image.png
具体是怎么做的呢?
![](https://img.haomeiwen.com/i14742426/eaafdcf17fe32d7c.png)
自动生成的代理类对应的每个函数会做这样一个操作,将当前函数传入到InvocationHandler实现类的invoke函数中,再在InvocationHandler 的 invoke函数中做统一权限等判断操作最后调用被代理类对应的函数
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 {
// 所有被代理对象的方法被执行,都会传入到invoke方法中
// 方法名称只要是set开头,进行权限检查
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("没有操作权限!");
}
}
return method.invoke(order, args);
}
}
网友评论