目录
1.什么是动态代理?
动态代理(Dynamic Proxy)是指在运行时动态生成代理类及其对象的机制,它允许在运行时创建代理对象并将方法调用转发给被代理对象。
2.动态代理和静态代理的区别
- 静态代理是在编译时指定代理对象,代理对象和被代理对象之间的关系是固定的。
- 动态代理是在运行时动态生成代理对象,代理对象和被代理对象之间的关系可以在运行时改变。
3.使用场景
- 动态代理:代理类是通过Java提供的反射机制动态生成的,不需要编写具体的代理类,只需提供接口定义和一个InvocationHandler接口的实现类,通过反射的方式,在运行时动态生成代理类并处理方法调用。
-
虚拟代理(Virtual Proxy):当需要延迟加载对象,减少资源占用或提高性能时,可以使用动态代理来创建一个虚拟代理。虚拟代理在访问对象之前进行实例化,并在需要时才加载真正的对象。
-
安全代理(Protection Proxy):当需要对方法进行安全性检查或权限验证时,可以使用动态代理来创建一个安全代理,控制对实际对象的访问。安全代理可以在调用实际对象之前进行权限验证,并决定是否执行方法调用。
-
日志记录(Logging):当需要在方法调用前后记录日志信息时,可以使用动态代理来创建一个代理对象,在方法调用前后记录相关的日志信息。这样可以对系统的运行进行监控、调试和分析。
-
AOP(Aspect-Oriented Programming):AOP是一种面向切面编程的技术,可以使用动态代理来实现AOP中的横切关注点(cross-cutting concerns)。通过动态代理,可以将横切关注点的代码和业务逻辑代码分离,实现更好的模块化和可维护性。
4.Java 中的动态代理机制
java.lang.reflect.Proxy
类:该类用于生成动态代理对象。java.lang.reflect.InvocationHandler
接口:该接口定义了代理对象的调用处理程序,通过实现该接口可以自定义代理对象的行为。
5.实现动态代理的步骤
- 创建一个实际的对象,即被代理对象。
- 创建一个实现
InvocationHandler
接口的调用处理程序,用于在代理对象的方法被调用时执行相应的逻辑。 - 使用
Proxy.newProxyInstance()
方法创建一个动态代理对象,该方法接收类加载器、接口数组和调用处理程序作为参数。 - 通过动态代理对象调用相应的方法来触发代理动作,代理对象会将方法调用委托给调用处理程序。
6.动态代理的局限性
- 代理对象只能代理实现了接口的对象,无法代理没有实现接口的对象。
- 被代理对象的非公共方法无法被代理,因为代理对象只能调用公共的方法。
7.代码示例
// 定义明星接口
interface Star {
void perform();
}
// 实现明星接口的大明星类
class TomCruise implements Star {
@Override
public void perform() {
System.out.println("Tom Cruise is performing!");
}
}
// 实现InvocationHandler接口的代理类
class Agent implements InvocationHandler {
private Object target; // 被代理的目标对象
public Agent(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Agent: Before method: " + method.getName());
Object result = method.invoke(target, args); // 调用目标对象的方法
System.out.println("Agent: After method: " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
TomCruise tomCruise = new TomCruise(); // 实例化大明星对象
Agent agent = new Agent(tomCruise); // 创建代理对象,传入大明星对象
// 创建动态代理对象,该代理对象实现了Star接口,调用处理程序为Agent对象
Star proxy = (Star) Proxy.newProxyInstance(
tomCruise.getClass().getClassLoader(), // 类加载器
tomCruise.getClass().getInterfaces(), // 实现的接口数组
agent); // 调用处理程序
proxy.perform(); // 通过动态代理对象调用perform()方法
}
}
在上面的示例中,我们首先定义了一个明星接口 Star
,其中有一个 perform()
方法用于表演。
然后我们创建了一个名为 TomCruise
的大明星类,实现了 Star
接口,并且在 perform()
方法中输出了相应的信息。
接着,我们创建了一个叫做 Agent
的代理类,它实现了 InvocationHandler
接口,用于代理 TomCruise
的工作。在 invoke()
方法中,我们在方法调用前后添加了一些额外的逻辑。
在 Main
类的 main()
方法中,我们创建了一个 TomCruise
对象和一个 Agent
对象,并将 Agent
对象传递给 Proxy.newProxyInstance()
方法来生成一个动态代理对象。
最后,我们通过动态代理对象 proxy
来调用 perform()
方法,代理对象将会执行 Agent
类中定义的前置和后置处理逻辑,并最终调用 TomCruise
中的 perform()
方法。
执行上述代码后,你将会看到如下输出:
Agent: Before method: perform
Tom Cruise is performing!
Agent: After method: perform
这个示例展示了一个大明星 TomCruise
和他的代理经纪人 Agent
的使用动态代理的场景。在代理对象的方法调用前后,代理经纪人可以添加额外的逻辑,比如在表演前进行准备工作或者在表演后进行收尾工作。