动态代理
动态代理是一种强大的技术,利用 反射机制 在运行时生成代理对象,允许开发者在不修改源代码的情况下对方法调用进行拦截和增强。动态代理在 AOP(面向切面编程)、RPC(远程过程调用)等领域有广泛的应用。
一、动态代理的基本概念
代理对象(Proxy Object):代理对象是指通过动态代理生成的对象,它实现了目标对象的所有接口,并且可以在方法调用前后添加额外的处理逻辑。
前端开发也有类似的逻辑:比如 Router 路由前后钩子封装配置、Axios 请求前后拦截封装配置等。
InvocationHandler:这是一个接口,用于定义代理对象的方法调用处理逻辑。每个代理对象在调用方法时,都会将调用转发给关联的
InvocationHandler
对象的invoke
方法。
二、动态代理的实现步骤
以下是使用 Java 动态代理的步骤:
定义接口和目标对象:首先定义一个接口及其实现类。
创建 InvocationHandler 实现类:定义一个实现
InvocationHandler
接口的类,编写代理逻辑。创建代理对象:使用
Proxy.newProxyInstance
方法生成代理对象。
三、示例代码
下面是一个简单的示例,展示了如何使用动态代理在方法调用前后添加日志。
定义接口和目标对象
package org.example;
public interface HelloService {
void sayHello(String name);
}
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
}
创建 InvocationHandler 实现类
package org.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class HelloServiceInvocationHandler implements InvocationHandler {
private final Object target;
public HelloServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
}
创建代理对象并使用
package org.example;
import java.lang.reflect.Proxy;
public class App {
public static void main(String[] args) {
// 创建目标对象
HelloService target = new HelloServiceImpl();
// 创建InvocationHandler
HelloServiceInvocationHandler handler = new HelloServiceInvocationHandler(target);
// 创建代理对象
HelloService proxy = (HelloService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
// 调用代理对象的方法
proxy.sayHello("Bob");
}
}
四、输出
运行上面的代码,输出将是:
Before method: sayHello
Hello, Bob
After method: sayHello
五、关键点解释
接口和目标对象:
HelloService
接口定义了一个方法sayHello
,实现类HelloServiceImpl
提供了具体实现。InvocationHandler 实现类:
HelloServiceInvocationHandler
实现了InvocationHandler
接口,在invoke
方法中添加了方法调用前后的日志输出。生成代理对象:使用
Proxy.newProxyInstance
方法生成代理对象。需要提供类加载器、目标对象实现的接口和InvocationHandler
实现。调用代理对象的方法:调用代理对象的方法会触发
InvocationHandler
的invoke
方法,在该方法中可以添加额外的逻辑。
六、动态代理的应用
- AOP(面向切面编程):动态代理是 AOP 的核心技术,通过代理对象在方法调用前后织入切面代码,实现如日志记录、事务管理等功能。
- RPC(远程过程调用):动态代理可以用来简化 RPC 的实现,通过代理对象将本地调用转换为远程调用。
- Mock 框架:在单元测试中,动态代理常用于创建模拟对象。
动态代理提供了一种灵活且强大的方式来在运行时对方法调用进行拦截和增强,极大地提高了代码的可维护性和可扩展性。