JDK动态代理
在认识JDK的动态代理之前,先来看看静态代理。静态代理的核心在于,在代理类里维护一个目标类的实列,在代理类的代理方法调用目标实列业务方法的前后实现代理逻辑。动态代理有JDK的动态代理和CGlIb的动态代理,JDK的动态代理前提是要目标类实现接口,通过Proxy.newProxyInstance(目标类类加载器,目标类实现的接口Class[], 持有目标对象的handler);来获取代理类。而CGlib代理不需要目标类实现接口,其通过修改目标类的节码生成代理子类来实现动态代理。
1.静态代理
客户端代码调用情况:
/**
* 静态代理
* 1.代理类和目标类实现共同的接口
* 2.代理类维护一个目标类的实列
* 3.客户端通过调用代理的方法实现代理逻辑
*/
public class Client {
public static void main(String[] args) {
Target target = new Target();
TargetProxy proxy = new TargetProxy(target);
proxy.work();
}
}
目标类代码:
public class Target implements Bins{
@Override
public void work() {
try {
Thread.sleep(1500);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("目标类业务方法");
}
}
代理类代码:
/**
* 代理类
* 1.代理类和目标类实现共同的接口
*/
public class TargetProxy implements Bins{
private final Target target;
public TargetProxy(Target target) {
this.target = target;
}
/**
* 在调用目标的前后完成代理业务逻辑
*/
@Override
public void work() {
long sTime = System.currentTimeMillis()/1000;
this.doSomething();
this.target.work();
long eTime = System.currentTimeMillis()/1000;
System.out.println("耗时:"+(eTime-sTime));
}
private void doSomething(){
System.out.println("代理业务逻辑");
}
}
功能接口:
public interface Bins {
void work() throws InterruptedException;
}
2.JDK动态代理
客户端代码调用情况:
public class Client {
public static void main(String[] args) {
ElectricCar car = new ElectricCar();
// 1.获取对应的ClassLoader
ClassLoader classLoader = car.getClass().getClassLoader();
// 2.获取ElectricCar 所实现的所有接口
Class[] interfaces = car.getClass().getInterfaces();
// 3.设置一个来自代理传过来的方法调用请求处理器,处理所有的代理对象上的方法调用
InvocationHandler handler = new InvocationHandlerImpl(car);
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, handler);
Vehicle vehicle = (Vehicle) proxy;
vehicle.drive();
}
}
这里的核心代码,Object proxy = Proxy.newProxyInstance(classLoader, interfaces, handler);其对应的源码主要脉络如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
}
实现代理核心逻辑:
2.1 通过 final Class<?>[] intfs = interfaces.clone();获取接口的class对象;
2.2 通过 Class<?> cl = getProxyClass0(loader, intfs);获取代理对象的calss对象;这里本质上是使用类加载器和接口的class对象来构建代理的class对象。
2.3 通过 final Constructor<?> cons = cl.getConstructor(constructorParams); 获取代理对象的构造器;
2.4 通过 cons.newInstance(new Object[]{h});创建代理对象并返回;
方法调用处理器
public class InvocationHandlerImpl implements InvocationHandler {
private ElectricCar car;
public InvocationHandlerImpl(ElectricCar car){
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理....");
method.invoke(car,null);
System.out.println("代理....");
return null;
}
}
3.CGlib代理
通过修改目标类的节码生成代理子类来实现动态代理。
4.相关问题
4.1 相比静态代理,动态代理的有点?
不需要提前实现代理类,这也是引入动态代理的原因。
4.2 JDK动态代理与CGlib动态代理的区别?
实现方式:JDK动态代理必须要求目标类实现接口,而CGlib无此限制,CGlib是利用字节码编辑技术来实现的。
使用场景:在目标类实现接口的场景才能使用JDK动态代理,否则使用CGlib代理。
性能:JDK 1.8之前CGlib由于JDK动态代理。1.8之后,相反。
4.3 使用场景有哪些?
Spring AOP、测试框架 mock、用户鉴权、日志、全局异常处理、事务。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报