动态代理是一种重要的 设计模式,它允许在运行时生成代理类来代替实际的类。动态代理主要通过反射机制实现,为开发者提供了一种灵活且强大的方式来实现 AOP(面向切面编程)等功能。
1.定义
动态代理是一种在运行时生成代理类的机制,这些代理类在程序运行时创建,而不是在编译时静态定义。 JDK 动态代理主要基于 Java 的反射机制,通过在运行时创建代理类和对象,实现对实际类的代理。
动态代理通常用于在不修改原始类代码的情况下,向现有类添加额外的功能,例如日志记录、性能监控、事务处理等。
2.原理
JDK 动态代理的核心在于 java.lang.reflect
包中的 Proxy
类和 InvocationHandler
接口。代理类的创建过程主要包括以下步骤:
- 定义接口: 定义一个业务接口,该接口将被动态代理类实现。
- 实现 InvocationHandler 接口: 创建一个实现
InvocationHandler
接口的类,该类中包含了对原始类方法的代理逻辑。 - 生成代理类: 使用
Proxy.newProxyInstance
方法生成代理类的实例,该方法需要传入类加载器、业务接口和InvocationHandler
实现。 - 调用代理方法: 通过代理类实例调用方法时,实际会调用到
InvocationHandler
中的invoke
方法,从而执行代理逻辑。
3.使用
1)定义业务接口
interface Stu {
void say(String name);
}
2)实现 InvocationHandler 接口
class HelloInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 增加前处理
System.out.println("执行方法前: " + method.getName());
// 执行原始方法 say
System.out.println("Hello, " + args[0]);
// 增加后处理
System.out.println("执行方法后: " + method.getName());
return null;
}
}
3)生成代理类
public class Demo {
public static void main(String[] args) {
// 创建 InvocationHandler 实例
HelloInvocationHandler invocationHandler = new HelloInvocationHandler();
// 生成代理类实例
Stu proxy = (Stu) Proxy.newProxyInstance(
Stu.class.getClassLoader(),
new Class[] { Stu.class },
invocationHandler
);
// 调用代理方法
proxy.say("Cheney");
}
}
输出结果:
执行方法前: say
Hello, Cheney
执行方法后: say
在上述示例中,HelloInvocationHandler
类实现了 InvocationHandler
接口,通过在代理方法的前后添加日志记录,这也就是传说中的 AOP 面向切面编程的效果。
4.优点
- 灵活性: 动态代理可以代理任意实现了接口的类,不受具体类的限制。
- 简化代码: 动态代理可以避免编写大量重复的代理类代码,减少代码冗余。
- 解耦合: 动态代理实现了代理逻辑和业务逻辑的解耦,使得代理类可以复用于不同的业务场景。
5.缺点
- 只能代理接口: JDK 动态代理只能代理实现了接口的类,对于没有实现接口的类无法进行代理。
- 性能相对较低: 由于动态代理是在运行时生成代理类,因此相比静态代理,其性能相对较低。
总结
JDK 动态代理是一种强大而灵活的设计模式,它通过在运行时生成代理类来实现对实际类的代理,为实现 AOP 等功能提供了便捷的方式。通过使用 Proxy
类和 InvocationHandler
接口,开发者可以轻松地创建动态代理。虽然 JDK 动态代理有一些限制,如只能代理实现了接口的类,性能相对较低等,但在大多数场景下,其优势远远大于缺点,使得它成为 Java 编程中不可或缺的一部分。