2.JDK动态代理类字节码的生成与解读

本文介绍了如何在Java中通过Proxy类生成动态代理类,以实现对目标类的方法拦截。通过设置系统属性或IDEAVM选项,可以保存生成的字节码文件。代理类继承自Proxy,实现了目标接口,并在方法调用时转发给InvocationHandler的invoke方法,从而在方法执行前后插入自定义逻辑。

highlight: arduino-light

获取动态代理类字节码

如果想要拿到动态代理类的源码,需要做以下操作:

在这一行代码前面

java Proxy.newProxyInstance(loader, interfaces, h);

添加如下代码

java System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

完整代码

```java package jdk代理;

import java.lang.reflect.Proxy; /* * @author: claude * @date: 2023/3/1 * @description: */ public class CalculatorProxyFactory{

public static Object getProxy(CalculatorConcrete calculator) {
    ClassLoader loader = calculator.getClass().getClassLoader();
    Class<?>[] interfaces = calculator.getClass().getInterfaces();
    CalculatorInvocationHandler h = new CalculatorInvocationHandler(calculator);
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    Object proxy = Proxy.newProxyInstance(loader, interfaces, h);
    return proxy;
}

public static void main(String[] args) {
    AddAndSubCalculator addAndSubCalculator = (AddAndSubCalculator) getProxy(new CalculatorConcrete());
    MultiplyAndDivCalculator multiplyAndDivCalculator = (MultiplyAndDivCalculator) getProxy(new CalculatorConcrete());
    addAndSubCalculator.add(1, 1);
    System.out.println("----------------------------");
    multiplyAndDivCalculator.div(4, 4);
}

} ```

或者在idea的VM options中 设置如下参数:

java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

然后生成我们的代理类即可,默认生成的包的路径是:com.sun.proxy。

```JAVA package jdk代理;

import java.lang.reflect.Proxy; /* * @author: claude * @date: 2023/3/1 * @description: */ public class CalculatorProxyFactory{

public static Object getProxy(CalculatorConcrete calculator) {
    ClassLoader loader = calculator.getClass().getClassLoader();
    Class<?>[] interfaces = calculator.getClass().getInterfaces();
    CalculatorInvocationHandler h = new CalculatorInvocationHandler(calculator);
    Object proxy = Proxy.newProxyInstance(loader, interfaces, h);
    return proxy;
}

public static void main(String[] args) {
    AddAndSubCalculator addAndSubCalculator = (AddAndSubCalculator) getProxy(new CalculatorConcrete());
    MultiplyAndDivCalculator multiplyAndDivCalculator = (MultiplyAndDivCalculator) getProxy(new CalculatorConcrete());
    addAndSubCalculator.add(1, 1);
    System.out.println("----------------------------");
    multiplyAndDivCalculator.div(4, 4);
}

} ```

执行完毕之后可以看到生成了1个$Proxy0.class。

反编译动态代理类字节码

将$Proxy0.class直接拖到idea即可反编译。

```java package com.sun.proxy;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import jdk代理.AddAndSubCalculator; import jdk代理.MultiplyAndDivCalculator;

public final class $Proxy0 extends Proxy implements AddAndSubCalculator, MultiplyAndDivCalculator { private static Method m1; private static Method m5; private static Method m2; private static Method m3; private static Method m4; private static Method m6; private static Method m0;

public $Proxy0(InvocationHandler var1) throws  {
    super(var1);
}

public final boolean equals(Object var1) throws  {
    try {
        return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
    } catch (RuntimeException | Error var3) {
        throw var3;
    } catch (Throwable var4) {
        throw new UndeclaredThrowableException(var4);
    }
}

public final int multiply(int var1, int var2) throws  {
    try {
        return (Integer)super.h.invoke(this, m5, new Object[]{var1, var2});
    } catch (RuntimeException | Error var4) {
        throw var4;
    } catch (Throwable var5) {
        throw new UndeclaredThrowableException(var5);
    }
}

public final String toString() throws  {
    try {
        return (String)super.h.invoke(this, m2, (Object[])null);
    } catch (RuntimeException | Error var2) {
        throw var2;
    } catch (Throwable var3) {
        throw new UndeclaredThrowableException(var3);
    }
}

public final int add(int var1, int var2) throws  {
    try {
        return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
    } catch (RuntimeException | Error var4) {
        throw var4;
    } catch (Throwable var5) {
        throw new UndeclaredThrowableException(var5);
    }
}

public final int sub(int var1, int var2) throws  {
    try {
        return (Integer)super.h.invoke(this, m4, new Object[]{var1, var2});
    } catch (RuntimeException | Error var4) {
        throw var4;
    } catch (Throwable var5) {
        throw new UndeclaredThrowableException(var5);
    }
}

public final int div(int var1, int var2) throws  {
    try {
        return (Integer)super.h.invoke(this, m6, new Object[]{var1, var2});
    } catch (RuntimeException | Error var4) {
        throw var4;
    } catch (Throwable var5) {
        throw new UndeclaredThrowableException(var5);
    }
}

public final int hashCode() throws  {
    try {
        return (Integer)super.h.invoke(this, m0, (Object[])null);
    } catch (RuntimeException | Error var2) {
        throw var2;
    } catch (Throwable var3) {
        throw new UndeclaredThrowableException(var3);
    }
}

static {
    try {
        m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
        m5 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("multiply", Integer.TYPE, Integer.TYPE);
        m2 = Class.forName("java.lang.Object").getMethod("toString");
        m3 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("add", Integer.TYPE, Integer.TYPE);
        m4 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("sub", Integer.TYPE, Integer.TYPE);
        m6 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("div", Integer.TYPE, Integer.TYPE);
        m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    } catch (NoSuchMethodException var2) {
        throw new NoSuchMethodError(var2.getMessage());
    } catch (ClassNotFoundException var3) {
        throw new NoClassDefFoundError(var3.getMessage());
    }
}

}

```

动态代理类代码解读

jdk代理原理概览

1.$Proxy0继承自Proxy,在Proxy中有类型为InvocationHandler的成员变量。

java protected InvocationHandler h;

Proxy中存在1个带参构造方法,参数是InvocationHandler。

java Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; }

调用$Proxy0的构造方法会调用Proxy的有参构造。从而把自定义的CalculatorInvocationHandler传递给父类。

java public $Proxy0(InvocationHandler var1) throws { super(var1); }

在自定义的CalculatorInvocationHandler中我们定义了一个成员变量calculatorConcrete,为被代理类的实例

2.调用代理类的add方法,

JAVA public static void main(String[] args) { AddAndSubCalculator addAndSubCalculator = (AddAndSubCalculator) getProxy(new CalculatorConcrete()); addAndSubCalculator.add(1, 1); }

其实就是调用$Proxy0#add。

生成的代理类$Proxy0会继承Proxy并实现AddAndSubCalculator, MultiplyAndDivCalculator接口。

并重写AddAndSubCalculator, MultiplyAndDivCalculator接口的所有方法。

以add方法为例实现如下:

在生成的代理类$Proxy0中会使用反射获取到被代理类CalculatorConcrete所有实现的接口的method对象,并作为代理类$Proxy0的成员变量。

```java private static Method m1; private static Method m2; private static Method m3; private static Method m4; private static Method m5; private static Method m6; private static Method m0; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("add", Integer.TYPE, Integer.TYPE); m4 = Class.forName("jdk代理.AddAndSubCalculator").getMethod("sub", Integer.TYPE, Integer.TYPE); m5 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("multiply", Integer.TYPE, Integer.TYPE); m6 = Class.forName("jdk代理.MultiplyAndDivCalculator").getMethod("div", Integer.TYPE, Integer.TYPE); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }

public final int add(int var1, int var2) throws  {
        try {
            //super是Proxy,h是CalculatorInvocationHandler
            //this是代理类对象
            //m3是接口AddAndSubCalculator#add方法
            // new Object[]{var1, var2}是入参
            return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

```

可以看到主要是这一句

java //super是Proxy,h是CalculatorInvocationHandler //this是代理类对象$Proxy0 //m3是接口AddAndSubCalculator#add方法 // new Object[]{var1, var2}是入参 return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});

由于我们的代理类$Proxy0继承了Proxy,所以我们自定义的CalculatorInvocationHandler可以通过super.h访问到。

所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。

所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。

所以在调用代理类的方法时,调用的总是CalculatorInvocationHandler的invoke方法。

5.在CalculatorInvocationHandler#invoke方法中。我们可以使用被代理类的实例CalculatorConcrete通过反射调用到被代理类CalculatorConcrete的原始方法,从而达到在被代理类CalculatorConcrete的方法前后动态织入代码的目的。

```java public class CalculatorInvocationHandler implements InvocationHandler { private CalculatorConcrete calculatorConcrete;

public CalculatorInvocationHandler(CalculatorConcrete calculatorConcrete) {
    this.calculatorConcrete = calculatorConcrete;
}

//参数1:即代理类对象
//参数2:即m3,是接口AddAndSubCalculator#add方法
//参数3:new Object[]{var1, var2}是入参
//calculatorConcrete是CalculatorInvocationHandler的成员变量
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("开始计算");
    Object result = method.invoke(calculatorConcrete, args);
    System.out.println("结束计算:" + result);
    return result;
}

} ```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值