从GraalVM到Quarkus系列-A002篇-GraalVM中的动态代理

6 篇文章 1 订阅
1 篇文章 0 订阅

从GraalVM到Quarkus系列

A000篇-忽悠你用GraalVM
A001篇-NativeImage相关的注解
B001篇-NativeImage相关的注解@TargetClass
A002篇-GraalVM中的动态代理


现状

在GraalVM NativeImage中目前只支持JDK的动态代理,而且不支持运行时动态代理


简单了解动态代理

这里已经有前人种树,我们摘果子…文章在->

在NativeImage中怎么用?

Mapper接口和实体类

代码如下:

package cbs.demo.mapper;

import cbs.demo.domain.Patient;

public interface PatientMapper {
    Patient getPatient(Integer id);
}
package cbs.demo.domain;

public class Patient {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

main 函数

代码如下(这里折叠了一些东西,后面会有完整代码在gitee):

在这里插入图片描述

mvn clean package native-image三连(具体可以看前面章节)

运行输出如下:
在这里插入图片描述

  1. 蓝色箭头是我们实际调用的地方
  2. 红色箭头是代理方法执行的第一个输出
  3. 黄色箭头是我们输出的调用的方法名
  4. 等等!!!
  5. 这他喵的不是和普通JDK动态代理一样么?
  6. 这不也是运行时动态代理的么?
    在这里插入图片描述

我们试下完全运行时的动态代理

在这里插入图片描述

  1. 代理的接口完全是由参数在运行是传入进行动态代理
  2. 这样避免NativeImage在静态分析时进行一些魔法操作
  3. 如果这样能成功那才算是运行时的动态代理
  4. 运行结果如下
    在这里插入图片描述
  5. 可以看到运行是失败的
  6. 而且明确说不支持运行时动态代理,且需要在构建时进行
  7. 因垂死听…那这两种有什么区别?
  8. 难道一开始那种写法动态代理不发生在运行时?
    在这里插入图片描述

深入剖析

  1. 我去搂了一眼GraalVM的代码,发现了这个骚操作
    在这里插入图片描述
  2. 这两个方法是Proxy类中间接被Proxy.getProxyClassProxy.newProxyInstance调用的
  3. 关于@TargetClass是干什么的去看B001的内容
  4. 这里在NativeImage模式下Proxy已经不是以前我们认识的Proxy了,newProxyInstance的逻辑在子方法getProxyConstructor中被修改了
  5. 它是从这一坨代码中取出的代理对象
    final Class<?> cl = ImageSingletons.lookup(DynamicProxyRegistry.class).getProxyClass(interfaces);
    try {
        final Constructor<?> cons = cl.getConstructor(InvocationHandler.class);
        if (!Modifier.isPublic(cl.getModifiers())) {
            cons.setAccessible(true);
        }
        return cons;
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
    
  6. 这坨代码大多数我们都认识,尤其是InvocationHandler,这就是动态代理的接口啊
  7. 但是ImageSingletonsDynamicProxyRegistry是干啥的? 因垂死听
  8. 这里有getProxyClass,那什么时候放进去的?
  9. 是不是有个addProxyClass?
    在这里插入图片描述
  10. 果然,接口DynamicProxyRegistry有个addProxyClass,而且有两个地方调用了它,盘它!!!
  11. 先盘DynamicProxyFeature.class下的,代码链接
    在这里插入图片描述
  12. 这里是处理proxy-config.json文件的,官方文档有讲怎么用json文件配置动态代理,这里不多做解释,文档讲的很清楚
  13. 然后再看SubstrateGraphBuilderPlugins.class下的,代码链接
    在这里插入图片描述
  14. 注释说的也很清楚,就是静态分析的时候扫描字符串常量,进行注册
  15. 什么字符串常量呢?继续找调用者
    在这里插入图片描述
  16. 找到了这两个字符串常量
  17. 也就是说,NativeImage在编译的时候,会将代码中有这两个字符串常量的动态代理自动注册,用的也是ImageSingletons.lookup(DynamicProxyRegistry.class).addProxyClass(interfaces)
  18. 这就解释了为什么我们明文写到代码中动态代理可以,而用参数传入进行动态代理不可以
  19. 因为明文写到代码中,NativeImage在编译的时候已经自动生成代理并添加到NativeImage中了,所以在实际运行时直接取出来就行,并没有进行实际的动态代理操作
    在这里插入图片描述
  20. 等等!!!你以为这样就完了么?
    在这里插入图片描述
  21. 我们总不能把所有的动态代理全部明文写到代码中啊,这咋办?
    在这里插入图片描述
  22. 这时候祭出我们在A001篇讲的Feature.beforeAnalysis方法
  23. 在这里直接手动注册Mapper,反射信息也加上,执行结果如下
    在这里插入图片描述
  24. 等等!!为什么他喵的传参数的方式又行了?
  25. 因为我们在Feature.beforeAnalysis方法中注册了动态代理类,在NativeImage静态分析阶段前就已经生成了,所以也不需要在运行时动态代理
  26. 这下终于写完了…

总结

  1. NativeImage中的动态代理想了好久怎么去写,中间还插播了B001篇讲@TargetClass,涉及的东西稍微有点多,我们最终目的是把MyBatis带到GraalVM世界里(呲个牛逼)
  2. 代码会传到gitee
  3. 觉得还可以的可以关注下,会持续更新的,大概每周一篇
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值