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、用户鉴权、日志、全局异常处理、事务。

posted @   有所_期待  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
点击右上角即可分享
微信分享提示