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

从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. 觉得还可以的可以关注下,会持续更新的,大概每周一篇
<think>好的,我现在需要帮助用户解决在Vue2项目中将接口返回的对象转换为Element-UI组件可使用的数组的问题。首先,我需要回忆一下用户提供的引用内容,看看是否有相关的信息可以直接使用。 用户提供的引用中有提到按需导入Element组件、表单验证、表格数据格式化以及一维数组转二维数组的方法。特别是引用[5]提到了Vue2中将一维对象数组转换为二维对象数组的基本操作,这可能与用户的问题相关。此外,引用[4]中的formatter函数可能用于表格数据格式化,但用户的问题更关注数据结构转换,所以可能需要结合数据处理方法。 接下来,我应该分步骤思考如何将接口返回的对象转换为Element-UI需要的数组结构。Element-UI的表格组件通常需要数组格式的数据,每个元素代表一行数据。例如,如果接口返回的是嵌套对象,可能需要将其扁平化,或者提取特定属性组成数组。 首先,用户需要通过接口获取数据,这通常使用axios或其他HTTP库。假设接口返回的是一个对象,例如: ```javascript { userInfo: { id: 1, name: '张三', age: 25 }, orders: [ { orderId: 'A001', date: '2023-10-01', amount: 100 }, { orderId: 'A002', date: '2023-10-02', amount: 200 } ] } ``` 而Element-UI的表格需要的数据可能是这样的数组: ```javascript [ { id: 1, name: '张三', orderId: 'A001', date: '2023-10-01', amount: 100 }, { id: 1, name: '张三', orderId: 'A002', date: '2023-10-02', amount: 200 } ] ``` 这意味着需要将userInfo和orders数组中的每个订单合并成新的对象数组。这时可以使用数组的map方法来处理。例如,遍历orders数组,将每个订单对象与userInfo合并。 另外,引用[5]中提到的转换方法可能涉及使用v-for指令或JavaScript的数组处理方法,如map、reduce等。例如,使用map将每个订单对象扩展,加入用户信息。 还需要考虑数据格式是否符合Element-UI组件的要求,比如日期可能需要格式化,这里可以结合引用[4]中的formatter函数,但用户的问题更关注结构转换,所以日期格式化可能不是重点,但可以作为补充步骤提及。 步骤可能包括: 1. 使用axios获取接口数据。 2. 在Vue的methods或生命周期钩子(如created)中处理数据。 3. 使用JavaScript数组方法转换数据结构,如map、reduce等。 4. 将处理后的数组绑定到Element-UI组件,如el-table。 可能需要处理的情况包括嵌套对象、数组展开、属性合并等。例如,如果接口返回的数据结构复杂,可能需要递归处理或提取特定字段。 还需要考虑Vue的响应式数据,确保转换后的数组是响应式的,可能需要使用Vue.set或直接替换整个数组。 最后,可能需要给出一个完整的示例,展示从获取数据到转换再到绑定到Element-UI表格的过程,并引用相关的引用内容,如引用[5]中的数组转换方法。</think>在Vue2项目中,将接口返回的对象转换为Element-UI组件可使用的数组,需通过以下步骤实现: --- ### 一、基础数据转换方法 假设接口返回的原始数据为: ```javascript { user: { id: 1001, name: '用户A', role: 'admin' }, logs: [ { time: 1640995200000, action: '登录' }, { time: 1641081600000, action: '修改资料' } ] } ``` #### 步骤实现: 1. **使用`map`方法重组数据结构** ```javascript // 在axios请求回调中处理 this.listData = response.data.logs.map(item => ({ userId: response.data.user.id, userName: response.data.user.name, actionTime: new Date(item.time).toLocaleString(), actionType: item.action })); ``` 2. **绑定到Element-UI表格** ```html <el-table :data="listData"> <el-table-column prop="userId" label="用户ID"></el-table-column> <el-table-column prop="userName" label="姓名"></el-table-column> <el-table-column prop="actionTime" label="操作时间" :formatter="formatDate"></el-table-column> <el-table-column prop="actionType" label="操作类型"></el-table-column> </el-table> ``` --- ### 二、复杂对象转换场景 若接口返回多层嵌套对象: ```javascript { department: '技术部', members: [ { info: { empId: 'E2001', name: '王工' }, projects: ['项目A', '项目B'] } ] } ``` #### 转换方法: ```javascript // 使用flatMap展开嵌套数组 this.tableData = response.data.members.flatMap(member => member.projects.map(project => ({ department: response.data.department, empId: member.info.empId, projectName: project })) ); ``` --- ### 三、特殊处理技巧 1. **日期格式化** 结合Element-UI表格的`formatter`属性(引用[4]): ```javascript methods: { formatDate(row, column, cellValue) { return cellValue ? dayjs(cellValue).format('YYYY-MM-DD HH:mm') : '-'; } } ``` 2. **保持响应式** 若动态修改数组,需使用`Vue.set`或`this.$set`: ```javascript this.$set(this, 'tableData', newArray); ``` --- ### 四、完整示例 ```javascript // Vue实例 new Vue({ data() { return { tableData: [] } }, created() { axios.get('/api/data').then(res => { this.tableData = res.data.members.map(member => ({ // 提取需要的字段 name: member.info.name, // 将对象转换为字符串 projects: member.projects.join(', ') })); }); } }); ``` --- ### 五、引用说明 - 转换时注意保持数据响应式(引用[5]) - 表格组件需按Element-UI规范配置`prop`字段(引用[3]) ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值