动态代理
概念
动态代理是一种在运行时动态生成代理对象的技术。
通过使用动态代理,可以在不修改原始类的情况下,对其方法进行增强或拦截,以实现一些额外的功能。
在 Java 中,动态代理是通过反射机制实现的。
Java 提供了两种方式来创建动态代理:基于接口的代理和基于类的代理。
基于接口的代理:使用 Java 提供的
java.lang.reflect.Proxy
类来创建代理对象。该类提供了一个静态方法newProxyInstance
,通过传入目标接口、类加载器和调用处理器来创建代理对象。代理对象实现了目标接口,并在方法调用时委托给调用处理器进行处理。基于类的代理:使用第三方库(如 CGLIB)来生成代理对象。CGLIB 通过生成目标类的子类来实现代理,覆盖了父类的方法,并在方法调用时插入额外的逻辑。
动态代理常用于 AOP(面向切面编程)和框架开发中,例如在事务管理、日志记录和性能监控等方面。通过代理,可以在方法的执行前后插入自定义的逻辑,而不需要修改原始类的代码。
动态代理撑起了java各种架构的半壁江山。
接口动态代理
接口动态代理,我在插件机制中设计了一套Demo。
具体代码见gitee:
https://gitee.com/fly2world_admin/plugin-demo-proxy.git
接口代理经典案例: Mybatis
具体思路如下:
- 创建接口
java
package top.mybatisx.plugin_proxy.plugin;
/**
* 考勤插件接口
*/
public interface ClockInPlugin {
// 安装
void install();
}
- 创建处理器,实现 InvocationHandler 接口,实现 invoke 代理函数
java
/**
* 考勤业务
*/
public class ClockInService implements InvocationHandler {
private ClockType clockType;
/**
* 考勤执行
*/
public ClockInService(ClockType clockType) {
this.clockType = clockType;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----------可定义拦截器---------");
if (args != null) {
for (Object arg : args) {
System.out.println("通过代理拿到了参数:" + arg);
}
}
// 初始化插件
ClockInPlugin clockInPlugin = switch (clockType) {
case sytem -> new ClockInPluginImpl();
case dingding -> new DingDingClockInPluginImpl();
case weixin -> new WeixinClockInPluginImpl();
};
return method.invoke(clockInPlugin, args);
}
}
- 利用 Proxy.newProxyInstance 构造代理对象
- 直接使用接口对象
java
public static void main(String[] args) {
// 调用考勤
ClockType clockType = ClockType.dingding;
// 构造动态代理
ClockInPlugin clockInPlugin = (ClockInPlugin) Proxy.newProxyInstance(ClockInPlugin.class.getClassLoader(), new Class[]{ClockInPlugin.class}, new ClockInService(clockType));
// 调用纯接口,更加纯粹
clockInPlugin.install();
clockInPlugin.turnData();
clockInPlugin.importData();
clockInPlugin.destory();
}
基于类的代理
- 使用第三方库(如 CGLIB)来生成代理对象。
- 使用Spring版的 CGLIB 生成代理。
注:使用cglib不支持 graalvm 生成可执行文件。