1、典型回答
动态代理(Dynamic Proxy)是一种在运行时动态生成代理对象的技术。它可以在不修改原始类的情况下,对原始类的方法进行拦截和增强
使用动态代理可以实现以下常用功能:
- AOP(面向切面编程):动态代理可以用于实现横切逻辑,例如日志记录、性能监控、事务管理等。通过在方法执行前后插入代理逻辑,可以实现对目标方法的增强
- 远程方法调用(RPC):动态代理可以用于远程方法调用框架,例如使用代理对象作为客户端的远程服务代理,将调用转发给实际的远程服务
- 动态权限校验:动态代理可以用于动态权限校验,例如在访问某个受限资源时,使用代理对象判断用户是否具有相应的权限。
注:例如,Spring 中的 AOP、声明式事务、MyBatis/MyBatis Plus 中的分页插件、Dubbo、Openfeign 都是动态代理的典型使用场景
动态代理 VS 静态代理
动态代理和静态代理的最大的区别是:静态代理是编译期确定的代理类,但是动态代理却是运行期确定的代理类,也就是说:
- 静态代理其实就是事先写好代理类,可以手工编写也可以使用工具生成,但它的缺点是每个业务类都要对应一个代理类,特别不灵活,也不方便
- 动态代理是指在程序运行期,动态地创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术
所以,动态代理和静态代理的效果都是一样的,但静态代理使用麻烦,而动态代理使用简单,后者也是现在编程中实现代理的主流方式
2、全面剖析
静态代理和动态代理的作用都是一样的,都是用于代理原对象,对原对象进行拦截和更多功能增强的,但静态代理的实现比较麻烦,需要事先写好代理类,并且为每个代理对象都事先写好代理类,所以比较麻烦,且维护性较差,而动态代理是一种在运行时动态生成代理对象的技术,它可以在不修改原始类的情况下,对原始类的方法进行拦截和增强,所以它也是程序中都使用的代理技术。
为了让大家更好地理解它们的区别,这里实现一个静态代理的示例给大家看下,具体实现如下:
在以上示例代码中,UserService 接口和 UserServicelmpl 类是被代理对象和实现类,UserServiceProxy 类是代理类,它实现了 UserService 接口,并在 save 方法中添加了额外的前置和后置逻辑。在静态代理中,手动创建了代理对象,将实际的业务调用委托给被代理对象执行。
动态代理的实现代码如下:
从上述代码可以看出,在Java 语言中,只需要实现 InvocationHandler 接口,并重写 invoke 方法就可以来实现动态代理了。并且动态代理是通用的,和业务代理对象(原对象)没有任何关联,所以写好一次的动态代理,可以代理所有对象,而不需要像静态代理那样,要给每个业务 (代理)方法都写代理代码。
3、知识扩展
JDK动态代理的底层实现主要依赖于 Java 的反射机制实现的
Java 的反射机制允许程序在运行时动态地获取类的信息(如成员变量、方法、构造函数等),并在运行时调用对象的方法或创建对象,如下源码所示:
但是,动态代理除了可以依靠反射机制实现之外,还可以使用字节码生成库来实现动态代理。字节码生成库允许我们在运行时生成字节码,从而创建动态代理对象。例如 CGLib,CGLib 是一个开源的字节码生成库,它可以在运行时扩展 Java 类并生成子类,从而实现动态代理的功能。