Rabbitmq调用FeignClient接口失败

文章目录

  • 一、框架及逻辑介绍
    • 1.背景服务介绍
    • 2.问题逻辑介绍
  • 二、代码
    • 1.A服务
    • 2.B服务
    • 3.C服务
  • 三、解决思路
    • 1.确认B调用C服务接口是否能正常调通
    • 2.确认B服务是否能正常调用A服务
    • 3.确认消息能否正常消费
    • 4.总结
  • 四、修改代码验证
    • 1.B服务异步调用C服务接口——失败
    • 2.将消费消息放到C服务中,消费时直接调用service——成功
  • 五、结论

走过路过大神帮忙给个正确解决方案~~~~~

一、框架及逻辑介绍

1.背景服务介绍

微服务结构,目前有A、B、C三个服务。

  • A服务:做一些工具类的功能
  • B服务:类似于门户,调用A、C服务来给到前端
  • C服务:基础模块,日志、权限、数据维护

2.问题逻辑介绍

  • A服务:实现blast功能,该功能是异步任务,需要几分钟的时间才能执行完成,所以采用了消息队列的方式通知功能完成,可查看数据。当代码执行完成之后通过rabbitmq发送消息到B服务
  • B服务:消费消息,调用C服务存储完成通知数据
  • C服务:提供FeignClient接口

二、代码

1.A服务

业务代码,详细的逻辑部分就不列出代码部分了, 测试确认无问题。

@Api(tags = "blast工具")
@RequiredArgsConstructor
@RequestMapping("blast")
@RestController
public class BlastController {

    private final BlastService blastService;

    @PostMapping("uniport")
    @ApiOperation("蛋白质序列对比")
    public ApiResponse<Boolean> check(@RequestBody BlastEntity blastEntity) {
        boolean flag = blastService.check(blastEntity);
        if(flag){
            return ApiResponse.success(flag);
        }else{
            return ApiResponse.failure("序列比对失败");
        }
    }

    @GetMapping("uniportDetail")
    @ApiOperation("蛋白质序列对比详情")
    public ApiResponse<BlastLogEntity> selectDetailById(@ApiParam("主键") @RequestParam("id") Integer id){
        return ApiResponse.success(blastService.selectDetailById(id));
    }
}

通过FeignClient提供功能接口给B服务(门户)

@FeignClient(name = "tool", url = "${customer.tool-url}")
public interface DataClient {

    @PostMapping("/blast/uniport")
    @ApiOperation("蛋白质序列对比")
    ApiResponse<Boolean> checkBlastUniprot(@RequestBody BlastEntity blastEntity);

    @GetMapping("/blast/uniportDetail")
    @ApiOperation("蛋白质序列对比详情")
    ApiResponse<BlastLogEntity> selectDetailById(@ApiParam("主键") @RequestParam("id") Integer id);
}

通过Rabbitmq发送消息

@Configuration
public class DirectRabbitMQConfig {

    //创建一个名为TestDirectExchange的Direct类型的交换机
    @Bean
    DirectExchange directExchange(){
        // durable:是否持久化,默认是false,持久化交换机。
        // autoDelete:是否自动删除,交换机先有队列或者其他交换机绑定的时候,然后当该交换机没有队列或其他交换机绑定的时候,会自动删除。
        // arguments:交换机设置的参数,比如设置交换机的备用交换机(Alternate Exchange),当消息不能被路由到该交换机绑定的队列上时,会自动路由到备用交换机
        return new DirectExchange(RabbitMqConstants.EXCHANGE_NAME,true,false);
    }
    //创建一个名为insertChassisDirectQueue的队列
    @Bean
    public Queue insertBlastDirectQueue(){
        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,有消息者订阅本队列,然后所有消费者都解除订阅此队列,会自动删除。
        // arguments:队列携带的参数,比如设置队列的死信队列,消息的过期时间等等。
        return new Queue(RabbitMqConstants.INSERT_BLAST_NAME,true);
    }

    //绑定交换机和队列
    @Bean
    Binding insertBlastDirect(){
        return BindingBuilder.bind(insertBlastDirectQueue()).to(directExchange()).with(RabbitMqConstants.INSERT_BLAST_KEY);
    }
}

2.B服务

消费消息,根据输出日志,可以看到消费消息成功。
但是走到apiClient.addLogMessage(logMessageEntity);不报错,C服务无响应,断点查看apiClient是可以看到C服务的信息localhost:8080的。

	@RabbitHandler
    @RabbitListener(bindings = {@QueueBinding(
            value = @Queue(value = INSERT_BLAST_NAME, durable = "true"),
            exchange = @Exchange(value = RabbitMqConstants.EXCHANGE_NAME),
            key = INSERT_BLAST_KEY)})
    public void insertBlast(Map map, Channel channel, Message message) {
        try {
            LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            BlastLogEntity blastLogEntity = TypeSwitchUtil.toSnakeObject(JSON.toJSONString(map), BlastLogEntity.class);
            if (null == blastLogEntity || StringUtils.isEmpty(blastLogEntity.getContent())) {
                LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());
            } else {
                LogMessageEntity logMessageEntity = new LogMessageEntity();
                logMessageEntity.setTargetId(blastLogEntity.getId());
                logMessageEntity.setUserId(String.valueOf(blastLogEntity.getUserId()));
                logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());
                logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());
                apiClient.addLogMessage(logMessageEntity);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
    }

3.C服务

@FeignClient(name = "api", url = "${customer.url}", configuration = FeignConfig.class)
public interface ApiClient {
    
    @PostMapping("/cms/logMessage/add")
    @ApiOperation("新增系统通知发送记录")
    ApiResponse<Boolean> addLogMessage(@RequestBody LogMessageEntity logMessageEntity);
}

三、解决思路

1.确认B调用C服务接口是否能正常调通

在B服务中,通过Controller暴露接口,调用C服务FeignClient的@PostMapping("/cms/logMessage/add") 接口,通过swagger测试,数据成功存储到数据库中。

——接口没有问题,服务之间通信也没有问题

2.确认B服务是否能正常调用A服务

在B服务中,调用A服务接口,测试成功。

——服务之间通信没有问题

3.确认消息能否正常消费

在B服务中,调用A服务接口,A服务输出发送消息日志。B服务消费输出日志。

——消息无问题

4.总结

在这里插入图片描述

  • 服务之间通信没有问题
    在这里插入图片描述

  • 消息提供和消费没有问题

综合猜测可能是线程或事务问题。

四、修改代码验证

1.B服务异步调用C服务接口——失败

	@RabbitHandler
    @RabbitListener(bindings = {@QueueBinding(
            value = @Queue(value = INSERT_BLAST_NAME, durable = "true"),
            exchange = @Exchange(value = RabbitMqConstants.EXCHANGE_NAME),
            key = INSERT_BLAST_KEY)})
    public void insertBlast(Map map, Channel channel, Message message) {
        try {
            LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            BlastLogEntity blastLogEntity = TypeSwitchUtil.toSnakeObject(JSON.toJSONString(map), BlastLogEntity.class);
            if (null == blastLogEntity || StringUtils.isEmpty(blastLogEntity.getContent())) {
                LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());
            } else {
                LogMessageEntity logMessageEntity = new LogMessageEntity();
                logMessageEntity.setTargetId(blastLogEntity.getId());
                logMessageEntity.setUserId(String.valueOf(blastLogEntity.getUserId()));
                logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());
                logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());
                CompletableFuture.runAsync(() -> {
		            apiClient.addLogMessage(logMessageEntity);
		        });
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
    }

经测试,未能解决问题。

2.将消费消息放到C服务中,消费时直接调用service——成功

	@RabbitHandler
    @RabbitListener(bindings = {@QueueBinding(
            value = @Queue(value = "blast.insert.queue", durable = "true"),
            exchange = @Exchange(value = "tool"),
            key = "blast.insert")})
    public void insertBlast(Map map, Channel channel, Message message) {
        try {
            LOGGER.info("【生成的消息-blast序列比对结果】:{}", map.toString());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            if (null == map || StringUtils.isEmpty(map.get("id").toString())) {
                LOGGER.warn("【生成的消息-blast序列比对结果】:{}", map.toString());
            } else {
                LogMessageEntity logMessageEntity = new LogMessageEntity();
                logMessageEntity.setTargetId(Integer.valueOf(map.get("id").toString()));
                logMessageEntity.setUserId(String.valueOf(map.get("user_id")));
                logMessageEntity.setMsgType(MsgStatusEnum.BLAST.getCode());
                logMessageEntity.setContent(MsgStatusEnum.BLAST.getMsg());
                logMessageService.save(logMessageEntity);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }
    }

在这里插入图片描述

五、结论

在使用消息队列(MQ)调用FeignClient服务时,采取以下步骤:

  • 配置消息队列:首先,确保已正确配置和启动您所使用的消息队列,例如 RabbitMQ 或者 Kafka。

  • 创建消息生产者:创建一个消息生产者,用于将消息发送到消息队列。您可以使用消息队列的客户端库或框架来实现此功能。

  • 发送消息:在需要调用FeignClient服务的地方,将消息发送到消息队列。消息中包含请求的相关信息,例如服务名称、路径、参数等。

  • 创建消息消费者:创建一个消息消费者,用于从消息队列接收消息并处理。

  • 处理消息:在消息消费者中,处理接收到的消息。根据消息中的请求信息,使用FeignClient来调用相应的服务。

虽然通过直接调用service的方式成功进行数据存储了,这样做也没有违背原有的逻辑。
但是问题仍然没有一个正确的解决方式,希望走过路过的大神能指点一二,在线求助。

走过路过大神帮忙给个正确解决方案~~~~~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024水资源、智慧城市与绿色发展国际会议(ICWRSCGD 2024)

2024水资源、智慧城市与绿色发展国际会议(ICWRSCGD 2024) 会议简介 2024年国际水资源、智慧城市与绿色发展大会&#xff08;ICWRSCGD 2024&#xff09;将在中国杭州举行。会议聚焦“水资源、智慧城市、绿色发展”这一最新研究领域&#xff0c;致力于促进世界顶级创新者、科学…

01 Redis的特性+下载安装启动

1.1 NoSQL NoSQL&#xff08;“non-relational”&#xff0c; “Not Only SQL”&#xff09;&#xff0c;泛指非关系型的数据库。 键值存储数据库 &#xff1a; 就像 Map 一样的 key-value 对。如Redis文档数据库 &#xff1a; NoSQL 与关系型数据的结合&#xff0c;最像关系…

代码随想录算法训练营第十一天 | 二叉树基础

代码随想录算法训练营第十一天 | 二叉树基础 文章目录 代码随想录算法训练营第十一天 | 二叉树基础1 二叉树的理论基础1.1 二叉树的类型1.2 二叉树的存储方式1.3 二叉树的遍历方式1.4 二叉树的定义 2 二叉树的递归遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历 3 二叉树的迭代遍历…

C++特殊类的设计

目录 一、不能被拷贝的类 二、只能在堆上创建对象的类 三、只能在栈上创建对象的类 四、不能被继承的类 五、只能创建一个对象的类(单例模式) 下面说几种特殊要求的类的设置&#xff0c;主要学习其中所运用的一些思想&#xff0c;融会贯通 一、不能被拷贝的类 C98可以将拷…

高质量谷歌seo外链平台有哪些?

明确的说&#xff0c;没有任何必要&#xff0c;这里说的没必要指的是没必要寻找什么高质量的外链平台 所谓高质量的外链平台是什么&#xff1f;你期待在这种平台发外链能获得什么效果&#xff1f;高质量的外链平台&#xff0c;无非就是网站排名高&#xff0c;能发相关的外链的平…

iOS推送通知

文章目录 一、推送通知的介绍1. 简介2. 通知的分类 二、本地通知1. 本地通知的介绍2. 实现本地通知3. 监听本地通知的点击 三、远程通知1. 什么是远程通知2. 为什么需要远程通知3. 远程通知的原理4. 如何做远程通知5. 远程通知证书配置6. 获取远程推送要用的 DeviceToken7. 测试…

外贸SOHO产品怎么选?海洋建站选品方法?

外贸SOHO应该如何选产品&#xff1f;跨境电商独立站选品策略&#xff1f; 越来越多的人选择通过外贸SOHO创业&#xff0c;将业务拓展到国际市场。然而&#xff0c;面对琳琅满目的外贸SOHO产品&#xff0c;许多初创企业主可能会感到困惑。海洋建站将为您提供一些建议&#xff0…

直播核心岗位基础内容

一.直播间核心岗位 1.直播间前端岗位 前端岗位分工 &#xff08;1&#xff09;主播岗位职责 &#xff08;2&#xff09;场控岗位职责 &#xff08;3&#xff09;助理岗位职责 中端岗位分工 &#xff08;1&#xff09;运营岗位职责 &#xff08;2&#xff09;中控岗位职责 …

2024年Java SpringBoot 计算机软件毕业设计题目推荐

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容&#xff1a;SpringBoot、Vue、SSM、HLM…

Hbuilder从gitlab上面拉取项目

要先下载TortoiseGit-2.15.0.0-64bit这个软件 在HBuilder中从GitLab上拉取项目&#xff0c;请按照以下步骤操作&#xff1a; 1. 打开HBuilder&#xff0c;点击左上角的“文件”菜单&#xff0c;然后选择“新建”->“项目”。 2. 在弹出的对话框中&#xff0c;选择“从Git导…

解决 [Vue warn]:Avoid mutating a prop directly 警告

错误信息 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “xxx” 错误原因 所有的 prop 都使得…

vue中使用canvas给图片绘制水印,即使下载图片也是带水印的

先看效果 话不多说直接上组件 1、Watermark.vue <template><div><canvas ref"canvas" :width"width" :height"height"></canvas></div> </template><script>export default {props: {// 图片地址ur…

Java服务端使用freemarker+wkhtmltoimage生成Echart图片

目录 1.通过 freemarker 将ftl转成html 1.1 freemarker 手册: 1.2 添加freemarker maven依赖 1.3 添加 echart-test.ftl 模版文件 1.4 添加 FreemarkerTool 工具类 1.5 添加测试main方法 1.6 运行,生成echart-test-时间戳.html 文件 2. 通过wkhtmltoimage将html 转为p…

【复现】JieLink+智能终端操作平台弱口令漏洞_28

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 JeLink智能终端操作平台 (JSOTC2016 fJeLink)是捷顺历经多年行业经验积累&#xff0c;集智能硬件技术视频分析技术、互联网技术等…

【HarmonyOS应用开发】ArkTS基础知识(三)

一、浅析ArkTS的起源和演进 1、引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xf…

如何解决服务器端口被占用的问题,减少带来的影响

在现代网络环境中&#xff0c;服务器扮演着至关重要的角色&#xff0c;其稳定性和安全性对企业的正常运营具有重要意义。然而&#xff0c;服务器端口被占用的问题却时常困扰着企业网络管理员。本文将深入探讨服务器端口被占用的影响&#xff0c;并提出相应的解决方案。 一、服务…

大数据学习之Redis、从零基础到入门(二)

二、Redis安装配置 1. VMWare本地虚拟机 VMWare准备的为64位 查看自己的VMWare是32位还是64位 getconf LONG_BIT 2. Redis的安装 2.1 系统选择 选择Linux系统 2.2 Linux版安装 2.2.1 Linux环境安装Redis必须先具备gcc编译环境 ①什么是gcc gcc是linux下的一个编译程序&…

Python模块与包:扩展功能、提高效率的利器

文章目录 一、引言1.1 模块与包对于Python开发的重要性1.2 Python作为拥有丰富生态系统的编程语言 二、为什么学习模块与包2.1 复用代码&#xff1a;利用现有模块与包加速开发过程2.2 扩展功能&#xff1a;通过模块与包提供的功能增强应用的能力 三、模块的使用3.1 导入模块&am…

网站域名一定要部署SSL证书吗?

随着互联网的发展&#xff0c;网络安全问题越来越受到重视。为网站域名部署SSL证书更是成为站长们维护网站安全的基础措施之一&#xff0c;但是这并非是强制性的&#xff0c;因此有不少人对部署SSL证书的必要性产生疑惑&#xff0c;网站域名一定要部署SSL证书吗&#xff1f;在本…

part1. jdk8新特性详解

1.Lambda //1.匿名内部类new Thread(new Runnable() {Overridepublic void run() {System.out.println("新线程中执行的代码&#xff1a;"Thread.currentThread().getName());}}).start();System.out.println("主线程中的代码:"Thread.currentThread().ge…