【实际开发10】- 远程调用 ( Feign )

news2024/11/18 1:43:36

目录

1. Feign 调用注意事项 - ★★★

1. 【原则】: 禁止遍历 - 多次跨服务调用接口 ( 提需求 : idList )

1. 单一数据查询 , 可直接用 Feign单一查询接口

2. List数据查询 , 需进行 Feign 数据转换 , 禁止遍历 Feign

3. stream() : 从List<对象> , 取出 id 和 name 组成 map 集合

4. for 循环 : 从List<对象> , 取出 id 和 Oject 组成 map 集合

2. 【原则】: 避免跨服务调用阻塞流程

1. 减少 跨服务 校验 ( 删除 - 资源占用 )

2. List 结果集 数据转换

1. 单查 feign API , 获取某模块数据 : map 容器化

2. 单查 feign API , 获取某模块数据 : cache 缓存 + map 容器化 ( 推荐 )

1. 对 feign API 数据源 作缓存 ( 主业务逻辑不做 )

2. 对全 业务 作缓存

3. 单查 feign API , 获取某模块数据 : 预热 + cache 缓存 + map 容器化

3. Feign 调用业务情景

1. CMP 配额模块

2. Iot 资产结构模块 - ( 单查 )

3. Iot 锚点数据转换 machineName / productType ( 业务内处理 × )

4. Iot 锚点转换 machine | camera ( 容器构建 map )

4. Feign 提示 / 异常

1. GET 请求以 @Requestbody 传参导致的异常 ( @R~body 用 POST )


1. Feign 调用注意事项 - ★★★


1. 【原则】: 禁止遍历 - 多次跨服务调用接口 ( 提需求 : idList )

路由 filter 过滤

限制 1 s 执行多少次 feign 调用

[
    {
        "args": {
            "key-resolver": "#{@remoteAddrKeyResolver}" , 
            "redis-rate-limiter.burstCapacity": "20" , 
            "redis-rate-limiter.replenishRate": "10"
        } , 
        "name": "RequestRateLimiter"
    } , 
    {
        "args": {
            "name": "default" , 
            "fallbackUri": "forward:/fallback"
        } , 
        "name": "Hystrix"
    }
]

 


1. 单一数据查询 , 可直接用 Feign单一查询接口


2. List<Object> 数据查询 , 需进行 Feign 数据转换 , 禁止遍历 Feign

但HashMap占内存比较大 , 不少人都更关注于HashMap所占的内存怎么计算。

运行了一下 , 没找到HashMap的极限容量 , 但就发现HashMap很耗内存 , 一下子就OutOfMemoryError了。

        Integer a = 1;
        long start = 0;
        long end = 0;
        // 先垃圾回收
        System.gc();
        start = Runtime.getRuntime().freeMemory();
        HashMap map = new HashMap();
        for (int i = 0; i < 1000000; i++) {
            map.put(i ,  a);
        }
        // 快要计算的时 , 再清理一次
        System.gc();
        end = Runtime.getRuntime().freeMemory();
        System.out.println("一个HashMap对象占内存:" + (end - start));

当添加2000000个item的时候 , 就内存溢出了。

1000000个item的HashMap就占内存接近60M了~~夸张

map - key 上限: 2^30 = 1 073 741 824 (10.7 亿)

 


3. stream() : 从List<对象> , 取出 id 和 name 组成 map 集合

     Map<String ,  String> collect = list
         .stream()
         .collect(Collectors.toMap(p -> p.getId() ,  p -> p.getName()));

Iot-emergency 应急管理

原始:

    /**
     * 资产结构数据处理
     * @return Map<Integer ,  String>
     */
    private Map<Integer ,  String> iotStructureMap(){
        IotStructureDTO iotStructureDTO = new IotStructureDTO();
        IotUser user = SecurityUtils.getUser();
        if (user != null) {
            iotStructureDTO.setTenantId(user.getTenantId());
        }
        HashMap<Integer ,  String> structureMap = new HashMap<>(128);
        R<List<IotStructureVO>> listR = remoteIotStructureService.queryIotStructureList(iotStructureDTO);
        if( 0 == listR.getCode() && !listR.getData().isEmpty()){
            for (IotStructureVO iotStructureVO : listR.getData()) {
                structureMap.put(iotStructureVO.getId() , iotStructureVO.getAddressPath());
            }
        }
        return structureMap;
    }

stream() 流处理:

    /**
     * 设备数据处理
     * @return Map<Integer ,  String>
     */
    private Map<Integer ,  String> machineDataMap(){
        MachineData machineData = new MachineData();
        machineData.setDelFlag(1);
        R<List<MachineData>> listR = remoteMachineDataService.feginList(machineData);
        if(0 == listR.getCode() && null != listR.getData() && !listR.getData().isEmpty()){
            return listR.getData()
                    .stream()
                    .collect(Collectors.toMap(MachineData::getMachineId ,  MachineData::getMachineName));
        }
        return new HashMap<>();
    }


4. for 循环 : 从List<对象> , 取出 id 和 Oject 组成 map 集合


2. 【原则】: 避免跨服务调用阻塞流程

示例:

if ("0".equals(iotAnchorDTO.getType())) {
    // 修改设备锚点状态 + 同步设备挂载资产id
    MachineData machineData = new MachineData();
    machineData.setMachineId(Integer.parseInt(iotAnchorDTO.getMachineId()));
    machineData.setStructureId(iotAnchorDTO.getStructureId());
    R<Boolean> update = remoteMachineDataService.update(machineData);
    if (0 == update.getCode()) {
        return Boolean.TRUE;
    } else {
        log.info("设备锚点状态同步异常");
        /* 新增拦截提示:"throw new IotAssetStructureException("remoteMachineDataService.update()-设备锚点资产结构ID同步异常")" */
    }
}
return Boolean.TRUE;


1. 减少 跨服务 校验 ( 删除 - 资源占用 )


2. List<xxxVO> 结果集 数据转换


1. 单查 feign API , 获取某模块数据 : map 容器化


2. 单查 feign API , 获取某模块数据 : cache 缓存 + map 容器化 ( 推荐 )


1. 对 feign API 数据源 作缓存 ( 主业务逻辑不做 )

例如 :

涉及 设备 status、摄像头 status 实时感知问题,不适合作较长时间的缓存,

此处只适合作时效性较短的缓存(过期时间 < 10 min)

@Override
@Transactional(rollbackFor = Exception.class)
public List<IotAnchorVO> selectListByCondition(IotAnchorDTO iotAnchorDTO) throws Exception {
    List<IotAnchorVO> iotAnchorVOList = iotAnchorMapper.selectListByCondition(iotAnchorDTO);
    if (null == iotAnchorVOList || iotAnchorVOList.isEmpty()) {
        return iotAnchorVOList;
    }
    try {
        // 设备数据信息 - 构建容器:machineMap<machineId,MachineData>
        Map<Integer, MachineData> machineMap = machineMap();
        // 摄像头数据信息 - 构建容器:cameraMap<machineId,DeviceChannel>
        Map<String, DeviceChannel> cameraMap = cameraMap();

        // 结果集数据处理
        for (IotAnchorVO iotAnchorVO : iotAnchorVOList) {
            // path 路径转换(AddressPath)
            IotStructure iotStructure = iotStructureMapper.selectById(iotAnchorVO.getStructureId());
            if (null != iotStructure) {
                if (iotStructure.getLevel() < 2) {
                    iotAnchorVO.setAddressPath(iotStructure.getName());
                } else {
                    String s = iotStructureServiceImpl.pathChanges(iotStructure.getPath(), iotStructure.getTenantId());
                    iotAnchorVO.setAddressPath(s + "/" + iotStructure.getName());
                }
            }
            // 普通设备数据转换
            if ("0".equals(iotAnchorVO.getType())) {
                // 添加设备默认状态:1-不在线
                iotAnchorVO.setMachineStatus("1");
                // 转换设备名称等设备相关基础信息
                if(null != iotAnchorVO.getMachineId()){
                    log.info("============iotAnchorVO.getMachineId():null===========");
                    continue;
                }
                MachineData mac = machineMap.get(Integer.parseInt(iotAnchorVO.getMachineId()));
                if (null != mac) {
                    if (null != mac.getMachineName()) {
                        iotAnchorVO.setMachineName(mac.getMachineName());
                    }
                    // 设备状态:0-在线 1-不在线
                    if (null != mac.getOnlineFlag()) {
                        iotAnchorVO.setMachineStatus(mac.getOnlineFlag().toString());
                    }
                    if (null != mac.getTypeId()) {
                        iotAnchorVO.setProTypeId(mac.getTypeId());
                    }
                }
                // 摄像头数据转换
            } else if ("1".equals(iotAnchorVO.getType())) {
                // 添加摄像头默认状态:1-不在线
                iotAnchorVO.setMachineStatus("1");
                // 转换摄像头名称等设备相关基础信息
                DeviceChannel deviceChannel = cameraMap.get(iotAnchorVO.getMachineId());
                if (null != deviceChannel) {
                    if (null != deviceChannel.getName()) {
                        if(StringUtils.isNotBlank(deviceChannel.getRemark())){
                            iotAnchorVO.setMachineName(deviceChannel.getRemark() +"(" + deviceChannel.getName() +")" );
                        }else {
                            iotAnchorVO.setMachineName(deviceChannel.getName());
                        }
                    }else {
                        if(StringUtils.isNotBlank(deviceChannel.getRemark())){
                            iotAnchorVO.setMachineName(deviceChannel.getRemark());
                        }
                    }
                    // 摄像头状态:0-不在线 1-在线 【警告:这里状态需要统一转换】
                    if ("1".equals(String.valueOf(deviceChannel.getOnline()))) {
                        iotAnchorVO.setMachineStatus("0");
                    }
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        log.info("设备/摄像头数据转换数异常...");
    }
    return iotAnchorVOList;
}


2. 对全 业务 作缓存


3. 单查 feign API , 获取某模块数据 : 预热 + cache 缓存 + map 容器化

 


3. Feign 调用业务情景


1. CMP 配额模块

        R<String> r = remoteTenantService.isLimit(userId);
        if (0 != r.getCode()) {
            return R.failed("调用用户服务时发生异常");
        }


2. Iot 资产结构模块 - ( 单查 )

    /**
     * 根据锚点id 查询锚点关联资产结构信息
     * @param structureId 锚点id
     * @return IotAnchorVO
     */
    @Override
    public List<IotAnchorVO> selectIotAnchorInfoByStructureId(Integer structureId) throws Exception {
        List<IotAnchorVO> iotAnchorVOS = iotAnchorMapper.selectIotAnchorInfoByStructureId(structureId);
        // 设备id转换name
        for(IotAnchorVO info:iotAnchorVOS){
            Integer machineId = info.getMachineId();
            // com.hzcloud.iot.common.core.constant.SecurityConstants.FROM_IN ----??
            String fromIn = SecurityConstants.FROM_IN;
            try {
                R<MachineData> one = remoteMachineDataService.getOne(machineId ,  com.hzcloud.iot.common.core.constant.SecurityConstants.FROM_IN);
                // 如果远程调用成功:转换MachineName信息
                if (null != one) {
                    String machineName = one.getData().getMachineName();
                    info.setMachineName(machineName);

                } else {
                    info.setMachineName("--");
                    log.info("remoteMachineDataService.getOne()数据转换异常");
                }
            } catch (Exception e) {
                throw new Exception("remoteMachineDataService.getOne()数据转换异常");
            }
        }
        return iotAnchorVOS;
    }


3. Iot 锚点数据转换 machineName / productType ( 业务内处理 × )

        /** ---------------------------通过资产结构id自己及子集的设备锚点信息-20.07.22------------------------------------*/
        IotStructureDTO iotStructureDTO = new IotStructureDTO();
        iotStructureDTO.setId(structureId);
        List<Integer> structureIdList = iotStructureServiceImpl.getStructureIdList(iotStructureDTO);
        // 将idlist转换(封装进去)为锚点信息的入参对象
        IotAnchorDTO iotAnchorDTO = new IotAnchorDTO();
        iotAnchorDTO.setStructureIdList(structureIdList);
        List<IotAnchorVO> iotAnchorVOList = iotAnchorMapper.selectTrdListByCondition(iotAnchorDTO);
        for (IotAnchorVO iotAnchorVO : iotAnchorVOList) {
            if(null != iotAnchorVO.getMachineId()){
                /*String str = iotAnchorService.changeMachineName(iotAnchorVO.getMachineId());
                iotAnchorVO.setMachineName(str);*/
                /** --------------------警告:后期更换idLIst查询接口 , 对比 MachineId , 进行数据转换-----------------------*/
                try {
                    R<MachineData> one = remoteMachineDataService.getOne(iotAnchorVO.getMachineId() ,  com.hzcloud.iot.common.core.constant.SecurityConstants.FROM_IN);
                    // 如果远程调用成功:返回MachineName信息
                    if (null != one.getData().getMachineName()) {
                        iotAnchorVO.setMachineName(one.getData().getMachineName());
                    }
                    if (null != one.getData().getTypeId()){
                        iotAnchorVO.setProTypeId(one.getData().getTypeId());
                    }
                } catch (Exception e) {
                    // throw new Exception("remoteMachineDataService.getOne()数据转换异常");
                    log.info("remoteMachineDataService.getOne()数据转换异常");
                }
            }
        }
        iotTrdPreviewVO.setMachineList(iotAnchorVOList);
        return iotTrdPreviewVO;
    }


4. Iot 锚点转换 machine | camera ( 容器构建 map )

    /**
     * 构建容器:machineMap<machineId,MachineData>
     * @return Map<Integer, MachineData>
     */
    private Map<Integer, MachineData> machineMap(){
        // 容器构建
        HashMap<Integer, MachineData> machineMap = new HashMap<>(128);
        // 获取普通设备在线状态
        MachineData machineData = new MachineData();
        /*List<Integer> structureIdList = new ArrayList<>();
        structureIdList.add(0, structureId);
        // 获取与资产结构idList关联的设备
        machineData.setStructureIdList(structureIdList);
        // 启用禁用【设备模块的机制】
        machineData.setDelFlag(1);*/
        R<List<MachineData>> onlineListFegin = remoteMachineDataService.getOnlineListFegin(machineData, com.linksame.iot.common.core.constant.SecurityConstants.FROM_IN);
        // 构建容器:machineMap<machineId,MachineData>
        if (0 == onlineListFegin.getCode() && !onlineListFegin.getData().isEmpty()) {
            for (MachineData datum : onlineListFegin.getData()) {
                if (null != datum.getMachineId()) {
                    machineMap.put(datum.getMachineId(), datum);
                }
            }
        } else {
            log.info("remoteMachineDataService.getOnlineListFegin().getCode = 1,数据转换异常");
        }
        return machineMap;
    }

    /**
     * 构建容器:cameraMap<machineId,DeviceChannel>
     * @return Map<String, DeviceChannel>
     */
    private Map<String, DeviceChannel> cameraMap(){
        // 容器构建
        HashMap<String, DeviceChannel> cameraMap = new HashMap<>(128);

        // 摄像头数据信息
        R<List<DeviceChannel>> channelList = remoteWvpService.getChannelList("","");
        // 构建容器:cameraMap<machineId,DeviceChannel>
        if(0 == channelList.getCode() && !channelList.getData().isEmpty()){
            for (DeviceChannel deviceChannel : channelList.getData()) {
                if (StringUtils.isNotBlank(deviceChannel.getId())) {
                    cameraMap.put(deviceChannel.getId(), deviceChannel);
                }
            }
        }else{
            log.info("remoteWvpService.getChannelList():数据转换异常");
        }
        return cameraMap;
    }


4. Feign 提示 / 异常


1. GET 请求以 @Requestbody 传参导致的异常 ( @R~body 用 POST )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185996.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于PS VR2和独占,开发者和分析师都怎么看

近期&#xff0c;索尼正式宣布了PS VR2首发游戏列表&#xff0c;共计37款游戏&#xff0c;其中包括备受关注的IP大作《地平线&#xff1a;山之召唤》等。从这37款首发阵容中可以看到一个现象&#xff0c;大部分游戏是非新作&#xff0c;而是已经在PS VR1或其它VR平台上线&#…

C++基础——C++数组

C基础——C数组C 数组声明数组初始化数组访问数组元素C 中数组详解C 数组 C 支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的…

【数据结构基础】线性表 - 链表

n个节点离散分配&#xff0c;彼此通过指针相连&#xff0c;每个节点只有一个前驱节点&#xff0c;每个节点只有一个后续节点&#xff0c;首节点没有前驱节点&#xff0c;尾节点没有后续节点。确定一个链表我们只需要头指针&#xff0c;通过头指针就可以把整个链表都能推出来。知…

设计模式-UML图

目录 2&#xff0c;UML图 2.1 类图概述 2.2 类图的作用 2.3 类图表示法 2.3.1 类的表示方式 2.3.2 类与类之间关系的表示方式 2&#xff0c;UML图 统一建模语言&#xff08;Unified Modeling Language&#xff0c;UML&#xff09;是用来设计软件的可视化建模语言。它的特…

Matlab pdetool

云溪岩绵迎彩霞,博主精神压力大呀,没人说说知心话啊,SCU物理要命啦........基本物理方程静电磁场交流电磁场热传导Options->ApplicationGeneric Scalar泛型标量Generic System通用系统Structural Mechanics,Plane Stress结构力学 - 平面应力Structural Mechanics,Plane Stra…

Flashback Oracle文档阅读

和Flashback相关的文档大多位于备份和恢复用户指南 和Oracle 数据库开发指南中。 基本概念 请参看备份和恢复用户指南的1.4 About Oracle Flashback Technology。 Oracle Flashback Technology的定义&#xff1a; A set of Oracle Database features that provide an additi…

Verilog HDL门级建模

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…

数字电路设计:Logicly 最新版Crack

Logicly有效地教授逻辑门 数字电路 — 使用 Logicly 现代直观的用户界面支持拖放、复制/粘贴、缩放等功能&#xff0c;可快速轻松地设计电路。 通过暂停模拟并在您逐步推进时观察信号传播来控制调试。 不用担心学生计算机上的多个平台。在 Windows 和 macOS 上安装 创建引人入…

子查询-MySQL

文章目录理解举例基本使用语法分类分类方式1单行子查询多行子查询分类方式2&#xff1a;单行子查询单行比较操作符代码示例HAVING 中的子查询CASE中的子查询子查询中的空值问题非法使用子查询多行子查询多行比较操作符代码示例相关子查询相关子查询执行流程代码示例EXISTS 与 N…

USART学习笔记

目录 1. USART框图 2. 传输帧图 3. 配置步骤 4.配置编码&#xff08;使用库函数&#xff09; 5. 函数调用缩略图 1. USART框图 2. 传输帧图 起始位的特征&#xff1a;时钟引脚CK处于低电平&#xff0c;TX引脚处于低电平&#xff0c;持续1个SCLK长度&#xff08;位长度&…

2020-ICLR-Memory-Based Graph Networks

2020-ICLR-Memory-Based Graph Networks Paper&#xff1a;https://arxiv.org/abs/2002.09518 Code: https://github.com/amirkhas/GraphMemoryNet 基于内存的图网络 图神经网络&#xff08;GNN&#xff09;是一类可对任意拓扑结构的数据进行操作的深度模型。 作者为GNN引入了…

Python类调用实例方法

通常情况下&#xff0c;我们习惯使用类对象调用类中的实例方法。但如果想用类调用实例方法&#xff0c;不能像如下这样&#xff1a;class CLanguage: definfo(self): print("我正在学 Python") #通过类名直接调用实例方法 CLanguage.info()运行上面代码&#xff0c;程…

线路板行业含铜废水处理,铜箔废水深度处理和铜回收

产品介绍 传统沉淀法不能满足日益提的环保要求(如电镀表三镍含量要求0.1mg/l以下)。针对特定重金属离子的特点&#xff0c;利用螯合树脂的特种功能基团与重金属离子形成络合物的特性&#xff0c;实现重金属离子的回收利用及深度去除。 CH-90Na对除铜镍铅锌钴锰等具有特定的选择…

GBASE亮相第四代英特尔® 至强® 可扩展处理器新品发布

1月11日&#xff0c;英特尔&#xff08;中国&#xff09;有限公司成功举办“芯加速 行至远”——第四代英特尔发布会。GBASE南大通用作为英特尔的长期战略合作伙伴&#xff0c;双方联合推出GBase 8a大规模分布式并行处理&#xff08;MPP&#xff09;数据库集群系统解决方案&…

在spring boot3中使用native image

文章目录简介安装GraalVM添加Native Image支持构建spring boot3应用总结简介 在之前spring boot3文章中我们介绍了&#xff0c;spring boot3的一个重要特性就是支持把spring boot3的应用编译成为GraalVM的Native Image。 今天我们用具体的例子来给大家演示一下如何正确的将sp…

nacos 删除过期实例源码分析

nacos 删除过期实例也是注册中心的一个重要功能&#xff0c;今天我们从入口到结束分析一下&#xff0c;首先确定删除的入口在服务端注册接口的源码里&#xff0c;此处可以参考&#xff1a;参考注册源码 一、注册入口 1、创建空服务 public void registerInstance(String name…

行测笔记(主要知识点)

文章目录&#xff1a; 一&#xff1a;言语理解 1.技巧关系 2.逻辑填空 二&#xff1a;判断推理 1.图形推理 2.定义判断 3.类比推理 4.逻辑判断 三&#xff1a;资料分析 1.增长率 2.增长量 3.比重 4.平均数 5.倍数与比值 三&#xff1a;数量关系 1.解题…

Nozomi 交付业界第一个物联网端点安全传感器

运营技术 (OT) 和物联网 (IoT) 安全提供商 Nozomi Networks 推出了业界首款 OT 和物联网端点安全传感器 Nozomi Arc&#xff0c;旨在以指数方式加快实现完全运营弹性的时间。 Nozomi Arc 旨在自动部署在组织需要可见性的任何地方的大量站点和设备上&#xff0c;添加了关于关键…

六个步骤教你用Xmind制作思维导图

XMind是国产优秀的思维导图软件&#xff0c;那么如何使用xmind制作思维导图呢&#xff1f;对于新手来说&#xff0c;首先就要正确安装Xmind&#xff1b;其次&#xff0c;就是要搞清楚使用XMind画思维导图的步骤和方法&#xff0c;当然在学习使用xmind画思维导图的过程中也可以学…

Redis 面试题总结

Redis是什么&#xff1f; Redis 是一个 key-value 存储系统&#xff0c;它支持存储的 value 类型相对更多&#xff0c;包括 string、list、set、zset&#xff08;sorted set --有序集合&#xff09;和 hash。这些数据结构都支持 push/pop、add/remove 及取交集并集和差集及更丰…