有关JDK动态代理的思考

本文探讨了JDK动态代理的原理,通过示例展示了如何使用Proxy.newProxyInstance创建代理类以实现方法增强。代理类通过继承Proxy并实现目标接口,能够进行类型转换。虽然未能完全理解JVM生成代理类的详细过程,但可以看出代理类的方法调用最终都委托给了InvocationHandler的invoke方法。这是一个关于Java反射和动态代理的深入学习案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDK动态代理

今天在学习MyBatis原理时,又看到熟人动态代理,于是萌生了深扒JDK动态代理源码的念头。参考了一些网上的资料也专门下载了JDK API

  1. JDK动态代理应用
  • 使用Proxy.getProxyInstance生成代理类,实现对被代理类的增强方法
// 上一段copy的demo的代码

public class MyInvocationHandle implements InvocationHandler {

    private Object target;

    public MyInvocationHandle(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行MyInvocationHandle中的invoke方法");

        System.out.print(method.getName());

        Object res = null;

        System.out.println("我是增强方法before");
        res = method.invoke(target, args);
        System.out.println("我是增强方法after");
        return res;
    }
}

public interface SomeService {

    void doSome();

    void doOther();
}

public class SomeServiceImp implements SomeService{

    @Override
    public void doSome() {
        System.out.println("执行doSome方法");
    }

    @Override
    public void doOther() {
        System.out.println("执行doOther方法");
    }
}

public class MyApp {

    public static void main(String[] args) {
        SomeService service = new SomeServiceImp();
        MyInvocationHandle invocation = new MyInvocationHandle(service);
        //生成代理增强类
        SomeService proxy = (SomeService)
        Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), invocation);

        proxy.doOther();
        proxy.doSome();
    }
}

//运行结果
执行MyInvocationHandle中的invoke方法
toString我是增强方法before
我是增强方法after
执行MyInvocationHandle中的invoke方法
doOther我是增强方法before
执行doOther方法
我是增强方法after
执行MyInvocationHandle中的invoke方法
doSome我是增强方法before
执行doSome方法
我是增强方法after

  1. 代理类生成原理
  • 这里有一个问题,为什么Proxy.newProxyInstance能生成一个SomeService的增强类,又为什么可以使用强制类型转换?
Class<?> cl = getProxyClass0(loader, intfs);
// 从源码不难看出生成代理类对象的是上面这一行,

//百度了一通拿到了$Proxy0类
public final class $Proxy0 extends Proxy implements SomeService {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    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 void doOther() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 void doSome() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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"));
            m4 = Class.forName("SomeService").getMethod("doOther");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("SomeService").getMethod("doSome");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
  • 从上面的Proxy0对象不难看出,这个类继承了Proxy类,实现了SomeService接口,就解释了为什么获取到的对象为什么可以强转为SomeService
  • 并且增强类中实现的方法实际代码都是调用的全局变量invocationHandler的invoke方法。
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    /**
        Proxy0的构造方法接收了一个InvocationHandler类
        对应前文newProxyInstance方法由反射类构造方法对象构建对象实例方法
        cons.newInstance(new Object[]{h})
    **/
  • 到这里还是没有解释清楚JVM是如何生成的增强类对象的,继续尝试深挖一下
    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

点了半天,愣是啥都没看懂,还是JVM相关知识储备不够,以后有机会再琢磨

锻炼一下自己的书写能力,可能文章不够优秀,大家见笑了。

参考文章:
https://blog.youkuaiyun.com/flyfelu/article/details/118354250
还有好多大佬的文章忘记记下来了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值