目录
一、什么是代理模式
代理模式是一种设计模式,它允许一个对象访问另外一个对象。代理对象通常通过包含真实对象的引用来控制对真实对象的操作。代理模式分为静态代理和动态代理两种。
二、静态代理
1.定义
静态代理是在编译时期就确定的代理类。代理类与目标类实现相同的接口。代理类手动编写,代理类的作用是调用目标类的方法,同时可以在方法调用前后加入一些操作。
2.实现
2.1 先定义一个UserService的接口,其中包含两个方法select()和update()。
public interface UserService {
public void select();
public void update();
}
2.2 UesrService接口的具体实现类:UserServiceImpl。
这是真实主题(真正的业务类):
//RealSubject 真实主题(真正的业务类)
public class UserServiceImpl implements UserService{
@Override
public void select() {
System.out.println("查询selectById");
}
@Override
public void update() {
System.out.println("更新update");
}
}
2.3 定义了一个名为UserServiceProxy 的静态代理类。
//代理
public class UserServiceProxy implements UserService{
//包含Subject真实的主题
private UserServiceImpl realUserService = new UserServiceImpl();
@Override
public void select() {
long begin = System.currentTimeMillis();
//调用真正的业务逻辑
realUserService.select();
long end = System.currentTimeMillis();
System.out.println("select()执行耗时"+(end-begin)+"毫秒");
}
@Override
public void update() {
realUserService.update();
}
这个代理类实现了UserService接口,并包含了一个UserServiceImpl 对象来执行实际的业务逻辑。在代理类中,可以在调用真实业务逻辑之前或之后添加额外的操作。
2.4 静态代理的优缺点:
优点:
- 编译期检查,容易发现问题。
- 代码清晰易读,易于维护。
缺点:
- 不灵活,修改或扩展目标类需要同时修改代理类。
- 存在大量的重复代码。
三、动态代理
1 定义
动态代理是在运行时生成代理类的。与静态代理不同,动态代理不需要手动编写代理类,而是使用Java的反射机制动态生成代理类。
2 实现
2.1 先定义一个OrderService 接口。
public interface OrderService {
public void create(int money,int uid);
}
2.2 OrderService接口的具体实现类:OrderServiceImpl 。
public class OrderServiceImpl implements OrderService{
@Override
public void create(int money, int uid) {
System.out.println("订单被创建");
}
}
2.3 定义了一个 PerformanceInvocationHandler 类。
//用于检测方法执行性能的Handler执行器
public class PerformanceInvocationHandler implements InvocationHandler{
private Object real;
public PerformanceInvocationHandler(Object real) {
this.real = real;
}
/**
* 参数proxy: 代理对象
* 参数method:当前执行的方法对象
* 参数args:参数列表
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long begin = System.currentTimeMillis();
//真实业务对象当前的执行方法(基于反射的方式)
Object returnValue = method.invoke(real, args);
long end = System.currentTimeMillis();
System.out.println("方法执行耗时"+(end - begin)+"毫秒!");
return returnValue;
}
}
PerformanceInvocationHandler类实现了InvocationHandler接口,用于动态代理模式中监控方法的执行性能。
invoke方法:该方法的作用是在方法调用前后添加额外的功能,例如计算方法的执行时间。
在 invoke 方法中,使用反射机制调用真实业务对象的目标方法 method.invoke(real, args)
,并记录执行时间。最后,将执行耗时打印出来。
2.4 使用 Java 动态代理来为OrderServiceImpl 类生成代理对象,并在方法调用前后进行性能监控。
public class Text01 {
public static void main(String[] args) {
//真实的主题对象
OrderServiceImpl realOrderService = new OrderServiceImpl();
//获取类加载器
ClassLoader classLoader = realOrderService.getClass().getClassLoader();
//接口列表
Class[] interfaces = realOrderService.getClass().getInterfaces();
//创建InvocationHandler对象(动态代理对象的执行逻辑)
PerformanceInvocationHandler h = new PerformanceInvocationHandler(realOrderService);
//创建一个代理对象(动态代理对象)
OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(classLoader, interfaces, h);
//调用方法
orderServiceProxy.create(1234, 0001);
}
}
使用Proxy.newProxyInstance方法创建代理对象。这个代理对象会实现OrderService接口,
并在调用方法时使用PerformanceInvocationHandler 中的invoke方法来处理。
四、静态代理与动态代理
对比维度 | 静态代理 | 动态代理 |
实现方式 | 代理类在编译期确定 | 代理类在运行时动态生成 |
代理类的数量 | 每个目标类对应一个代理类 | 一个代理类可以代理多个目标类 |
编写难度 | 需要手动编写代理类,重复代码多 | 只需编写一个InvocationHandler实现类 |
性能 | 性能较高,不涉及反射 | 性能较低,依赖反射机制 |
灵活性 | 不灵活,目标类变化时代理类需同步修改 | 灵活,目标类变化时无需修改代理类 |
五、总结
- 静态代理适用于结构简单、需求明确的场景,如对固定业务逻辑的增强。
- 动态代理适用于复杂、需求变化频繁的场景,特别是在AOP(面向切面编程)中应用广泛。