Redis:发布(pub)与订阅(sub)实战

前言

Redis发布订阅(Pub/Sub)是Redis提供的一种消息传递机制,它使用“发布者-订阅者”(publisher-subscriber)模式来处理消息传递。在这种模式下,发布者将消息发布到一组订阅者中,而无需关心谁是订阅者,也不需要知道订阅者是否收到了消息。
在这里插入图片描述

发布者和订阅者模式允许多个客户端之间建立一个复杂的通信拓扑。在这种模式下,发布者可以发布消息到一个特定的主题,订阅者可以订阅一个或多个主题,并在发布者发布消息时收到消息。由于发布者和订阅者不必直接连接,因此发布者和订阅者可以完全独立地运行,只要它们都连接到Redis实例即可。

Redis发布订阅支持多种消息类型,包括文本、字节数组和数字等。 Redis还支持订阅者识别特定消息,通过模式匹配功能,可以基于主题模式或模式来检索消息。Redis还提供了许多API来帮助您实现发布/订阅模式,因此您可以使用Redis的发布/订阅功能来构建分布式应用程序。

Redis Pub/Sub(发布/订阅) 命令

Redis发布/订阅(Pub/Sub)分为两种

  • 第一种基于频道(Channel)的发布/订阅。
  • 第二种基于模式(pattern)的发布/订阅

确实,Redis提供了一系列的Pub/Sub命令来支持基于频道和基于模式的发布/订阅模式。以下是一些常用的Pub/Sub命令:

基于频道的发布/订阅

发布消息到指定频道

PUBLISH channel message

例如:

PUBLISH my-channel "Hello, Redis!"

这将向名为my-channel的频道发布消息"Hello, Redis!"。

订阅一个或多个频道

SUBSCRIBE channel channel ...

例如:

SUBSCRIBE my-channel your-channel

这将订阅my-channelyour-channel两个频道。

取消订阅一个或多个频道

UNSUBSCRIBE [channel channel ...]

例如:

UNSUBSCRIBE my-channel your-channel

这将取消订阅my-channelyour-channel两个频道。

基于模式的发布/订阅

订阅一个或多个匹配模式

PSUBSCRIBE pattern pattern ...

例如:

PSUBSCRIBE news-*

这将订阅所有以news-开头的频道。

取消订阅一个或多个匹配模式

PUNSUBSCRIBE [pattern pattern ...]

例如:

PUNSUBSCRIBE news-*

这将取消订阅所有以news-开头的频道。

注意:Pub/Sub命令可以在客户端和服务器之间进行通信,用于实现消息的发布和订阅。这些命令是异步执行的,发送命令后,订阅者将在接收到消息时收到通知。 Pub/Sub是一个强大的工具,用于实现实时消息传递和事件通知。

实战示例

基于MessageListener实现

创建消息接收者

创建一个接收消息的Bean。

package com.example.demo.redis;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;/*** 实现MessageListener的监听类*/
@Slf4j
@Component
public class RedisMessageSubscriber implements MessageListener {@Autowiredprivate MessageProcessor messageProcessor;@Overridepublic void onMessage(Message message, byte[] pattern) {String channel = new String(message.getChannel());String body = new String(message.getBody());log.info("@@ 当前执行的方法:onMessage");// 处理消息messageProcessor.processMessage(channel, body);}}

创建消息处理器

创建一个处理接收到的消息的Bean。

package com.example.demo.redis;
import org.springframework.stereotype.Service;@Service
public class MessageProcessor {public void processMessage(String channel, String message) {System.out.println("Received message: " + message + " from channel: " + channel);// 在这里进行具体的消息处理逻辑}
}

创建消息发送者

创建一个发送消息的Bean。

Redis有两种发布/订阅模式:

  • 基于频道(Channel)的发布/订阅
  • 基于模式(pattern)的发布/订阅
package com.example.demo.redis;// RedisMessagePublisher.javaimport org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;@Component
public class RedisMessagePublisher {@Autowiredprivate RedisTemplate<String, String> redisTemplate;public void publishMessage(String channel, String message) {// 基于模式(pattern)的发布/订阅// redisTemplate.convertAndSend("your-pattern-channel-1", "Hello, Redis!");// 基于频道(Channel)的发布/订阅redisTemplate.convertAndSend(channel, message);}
}

使用消息发送者发送消息

在需要发送消息的地方注入RedisMessagePublisher并使用它来发送消息。

package com.example.demo.redis;// MessageController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api/message")
public class MessageController {@Autowiredprivate RedisMessagePublisher messagePublisher;@GetMapping("/send")public String sendMessage(@RequestParam(value = "channel") String channel , @RequestParam(value = "messgage") String messgage) {messagePublisher.publishMessage("your-channel", "Hello, Redis!");messagePublisher.publishMessage(channel, messgage);return "Message sent successfully!";}
}

相关原理说明

  • 发布/订阅模型: Redis提供了一种发布/订阅(Pub/Sub)模型,其中消息发送者(发布者)将消息发送到一个或多个通道,而消息接收者(订阅者)则监听一个或多个通道以接收消息。
  • 消息监听器: RedisMessageSubscriber 实现了 MessageListener 接口,它监听指定通道上的消息。在这里,我们将接收到的消息传递给 MessageProcessor 进行处理。
  • 消息处理器: MessageProcessor 是一个简单的服务,用于处理接收到的消息。在实际应用中,你可以在这里添加业务逻辑来处理消息。
  • 消息发布者: RedisMessagePublisher 用于发布消息到指定的通道。在 sendMessage 方法中,我们使用 convertAndSend 方法将消息发送到名为 “your-channel” 的通道。
  • 消息发送端点: MessageController 是一个简单的REST控制器,用于触发消息发送。在这里,我们通过调用 messagePublisher.publishMessage 来发送消息。

总体来说,这个实现充分利用了Redis的发布/订阅功能,通过将消息发送者、消息接收者和消息处理器分离,使系统更加模块化和灵活。

RedisConfig配置

package com.example.demo.redis;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;@Slf4j
@Configuration
public class RedisConfig {/*** 配置订阅* 基于MessageListenerAdapter和RedisMessageListenerContainer* @param redisMessageSubscriber* @return*/@Beanpublic MessageListenerAdapter messageListenerAdapter(RedisMessageSubscriber redisMessageSubscriber) {return new MessageListenerAdapter(redisMessageSubscriber, "handleMessage");}@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,MessageListenerAdapter messageListenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);// 添加消息监听器和监听的频道// 基于频道的发布/订阅:container.addMessageListener(messageListenerAdapter, new ChannelTopic("your-channel"));// 基于模式的发布/订阅:container.addMessageListener(messageListenerAdapter, new PatternTopic("your-pattern-*"));return container;}/*** 基于MessageListener的配置* 直接使用RedisMessageSubscriber* @param connectionFactory* @param redisMessageSubscriber* @return*/@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,  RedisMessageSubscriber redisMessageSubscriber) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);// 在这里设置你的动态频道名称,可以从配置文件或其他地方获取String dynamicChannel = "your-channel";// 基于频道的发布/订阅:ChannelTopic channelTopic = new ChannelTopic(dynamicChannel);// 基于模式的发布/订阅:// container.addMessageListener(redisMessageSubscriber, new PatternTopic("your-pattern-*"));// 添加消息监听器和监听的动态频道container.addMessageListener(redisMessageSubscriber, channelTopic);return container;}//    /**
//     * 多频道示例
//     * @param connectionFactory
//     * @param redisMessageSubscriber
//     * @return
//     */
//    @Bean
//    public RedisMessageListenerContainer redisMessageListenerContainerMoreTopic(
//            RedisConnectionFactory connectionFactory,
//            RedisMessageSubscriber redisMessageSubscriber
//    ) {
//        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//        container.setConnectionFactory(connectionFactory);
//
//        // 在这里设置你的动态频道名称列表,可以从配置文件或其他地方获取
//        List<String> dynamicChannels = Arrays.asList("channel1", "channel2", "channel3");
//
//        // 创建包含所有频道的ChannelTopic列表
//        List<ChannelTopic> channelTopics = createChannelTopics(dynamicChannels);
//
//        // 添加消息监听器和监听的多个频道
//        for (ChannelTopic channelTopic : channelTopics) {
//            container.addMessageListener(redisMessageSubscriber, channelTopic);
//        }
//
//        return container;
//    }
//
//    private List<ChannelTopic> createChannelTopics(List<String> channelNames) {
//        // 使用动态频道名称创建ChannelTopic列表
//        List<ChannelTopic> channelTopics = new ArrayList<>();
//        for (String channelName : channelNames) {
//            channelTopics.add(new ChannelTopic(channelName));
//        }
//        return channelTopics;
//    }
}

这段代码是用于配置并创建 RedisMessageListenerContainer 的方法。RedisMessageListenerContainer 是 Spring Data Redis 提供的一个用于监听 Redis 消息的容器。以下是对代码的详细解释:

方法签名

  • RedisConnectionFactory connectionFactory:这是用于创建 Redis 连接的工厂。
  • RedisMessageSubscriber redisMessageSubscriber:这是一个 Redis 消息订阅者,用于处理接收到的消息。

创建 RedisMessageListenerContainer 实例

RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 
container.setConnectionFactory(connectionFactory);
  • 创建一个新的 RedisMessageListenerContainer 实例。
  • connectionFactory 设置为容器的连接工厂,用于创建连接到 Redis 的连接。

设置动态频道名称

String dynamicChannel = "your-channel";
  • 定义一个动态频道名称,可以从配置文件或其他地方获取。

创建 ChannelTopic 对象

ChannelTopic channelTopic = new ChannelTopic(dynamicChannel);
  • 创建一个 ChannelTopic 对象,表示基于频道的发布/订阅,其中 dynamicChannel 是频道名称。

添加消息监听器和频道

container.addMessageListener(redisMessageSubscriber, channelTopic);
  • redisMessageSubscriber 添加为消息监听器,用于处理接收到的消息。
  • 指定要监听的频道,这里使用了基于频道的发布/订阅模式。

返回 RedisMessageListenerContainer 实例

return container;
  • 返回配置好的 RedisMessageListenerContainer 实例。

通过以上步骤,这段代码的目的是创建一个配置好的 RedisMessageListenerContainer,该容器已设置好连接工厂、消息监听器以及要监听的动态频道。当 Redis 中的指定频道发布消息时,redisMessageSubscriberonMessage 方法将被调用来处理消息。这是一种基于频道的发布/订阅模式,允许应用程序实时地接收并处理消息。

自定义监听的回调函数

创建消息接收者

不需要实现MessageListener接口

package com.example.demo.redis;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 自定义的监听类*/
@Slf4j
@Component
public class RedisMessageCustomSubscriber {@Autowiredprivate MessageProcessor messageProcessor;/*** 自定义的回调函数* @param message* @param channel*/public void handleMessage(String message, String channel) {log.info("@@ 当前执行的方法:handleMessage");messageProcessor.processMessage(channel, message);}
}

RedisConfig配置

package com.example.demo.redis;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;@Slf4j
@Configuration
public class RedisConfig {/*** 配置订阅* 基于MessageListenerAdapter和RedisMessageListenerContainer* @param redisMessageSubscriber* @return*/@Beanpublic MessageListenerAdapter messageListenerAdapter(RedisMessageSubscriber redisMessageSubscriber) {return new MessageListenerAdapter(redisMessageSubscriber, "handleMessage");}@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,MessageListenerAdapter messageListenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);// 添加消息监听器和监听的频道// 基于频道的发布/订阅:container.addMessageListener(messageListenerAdapter, new ChannelTopic("your-channel"));// 基于模式的发布/订阅:container.addMessageListener(messageListenerAdapter, new PatternTopic("your-pattern-*"));return container;}//    /**
//     * 基于MessageListener的配置
//     * 直接使用RedisMessageSubscriber
//     * @param connectionFactory
//     * @param redisMessageSubscriber
//     * @return
//     */
//    @Bean
//    public RedisMessageListenerContainer redisMessageListenerContainer(
//            RedisConnectionFactory connectionFactory,  RedisMessageSubscriber redisMessageSubscriber) {
//
//        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//        container.setConnectionFactory(connectionFactory);
//
//        // 在这里设置你的动态频道名称,可以从配置文件或其他地方获取
//        String dynamicChannel = "your-channel";
//
//        // 基于频道的发布/订阅:
//        ChannelTopic channelTopic = new ChannelTopic(dynamicChannel);
//
//        // 基于模式的发布/订阅:
//        // container.addMessageListener(redisMessageSubscriber, new PatternTopic("your-pattern-*"));
//
//        // 添加消息监听器和监听的动态频道
//        container.addMessageListener(redisMessageSubscriber, channelTopic);
//
//        return container;
//    }//    /**
//     * 多频道示例
//     * @param connectionFactory
//     * @param redisMessageSubscriber
//     * @return
//     */
//    @Bean
//    public RedisMessageListenerContainer redisMessageListenerContainerMoreTopic(
//            RedisConnectionFactory connectionFactory,
//            RedisMessageSubscriber redisMessageSubscriber
//    ) {
//        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//        container.setConnectionFactory(connectionFactory);
//
//        // 在这里设置你的动态频道名称列表,可以从配置文件或其他地方获取
//        List<String> dynamicChannels = Arrays.asList("channel1", "channel2", "channel3");
//
//        // 创建包含所有频道的ChannelTopic列表
//        List<ChannelTopic> channelTopics = createChannelTopics(dynamicChannels);
//
//        // 添加消息监听器和监听的多个频道
//        for (ChannelTopic channelTopic : channelTopics) {
//            container.addMessageListener(redisMessageSubscriber, channelTopic);
//        }
//
//        return container;
//    }
//
//    private List<ChannelTopic> createChannelTopics(List<String> channelNames) {
//        // 使用动态频道名称创建ChannelTopic列表
//        List<ChannelTopic> channelTopics = new ArrayList<>();
//        for (String channelName : channelNames) {
//            channelTopics.add(new ChannelTopic(channelName));
//        }
//        return channelTopics;
//    }
}

这段代码配置了两个 @Bean 方法,一个用于创建 MessageListenerAdapter 实例,另一个用于创建 RedisMessageListenerContainer 实例。以下是详细解释:

创建 MessageListenerAdapter 实例

@Bean
public MessageListenerAdapter messageListenerAdapter(RedisMessageSubscriber redisMessageSubscriber) {return new MessageListenerAdapter(redisMessageSubscriber, "handleMessage");
}
  • 通过 @Bean 注解创建一个 MessageListenerAdapter 实例。
  • RedisMessageSubscriber 对象传递给构造函数,表示这个适配器将调用 RedisMessageSubscriber 的方法来处理消息。
  • 第二个参数 "handleMessage" 表示要调用的消息处理方法的名称。

创建 RedisMessageListenerContainer 实例

@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,MessageListenerAdapter messageListenerAdapter
) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);
  • 通过 @Bean 注解创建一个 RedisMessageListenerContainer 实例。
  • RedisConnectionFactory 传递给构造函数,表示这个容器将使用的连接工厂。

添加消息监听器和频道

// 添加消息监听器和监听的频道
// 基于频道的发布/订阅:
container.addMessageListener(messageListenerAdapter, new ChannelTopic("your-channel"));// 基于模式的发布/订阅:
container.addMessageListener(messageListenerAdapter, new PatternTopic("your-pattern-*"));
  • 使用 container.addMessageListener 方法添加消息监听器(messageListenerAdapter)。
  • 第一个参数是消息监听器适配器,它会调用 RedisMessageSubscriberhandleMessage 方法来处理消息。
  • 第二个参数是 ChannelTopic 对象,表示基于频道的发布/订阅模式,监听指定的频道。
  • 第三个参数是 PatternTopic 对象,表示基于模式的发布/订阅模式,监听指定模式的频道。

返回 RedisMessageListenerContainer 实例

return container;
  • 返回配置好的 RedisMessageListenerContainer 实例。

通过这样的配置,RedisMessageListenerContainer 已经设置好了连接工厂和消息监听器,并分别基于频道和基于模式的发布/订阅模式来监听相应的消息。当 Redis 中的指定频道发布消息时,handleMessage 方法将被调用来处理消息。

区别

MessageListenerAdapterRedisMessageListenerContainer 是 Spring Data Redis 提供的两个重要组件,用于实现 Redis 消息监听的机制。

MessageListenerAdapter

MessageListenerAdapter 是一个适配器,用于将普通的 Java 对象(POJO)转换为 Redis 消息监听器。它通过反射调用目标对象的方法来处理接收到的消息。在你的 POJO 类中,你可以定义一个或多个方法来处理不同类型的消息。

主要特点和用法:

  • 将普通的 Java 对象转换为 Redis 的消息监听器。
  • 可以指定调用目标对象的特定方法来处理消息。
  • 通过设置消息转换器,可以支持多种消息格式,如 JSON、XML 等。
  • 提供了一种简化消息处理逻辑的方式,避免了直接实现 MessageListener 接口的繁琐性。

RedisMessageListenerContainer

RedisMessageListenerContainer 是 Spring 提供的容器,用于管理 Redis 消息的监听器。它可以注册一个或多个消息监听器,并在接收到消息时调用相应的处理方法。该容器还负责管理连接到 Redis 的连接工厂,以及监听的频道或模式。

主要特点和用法:

  • 管理 Redis 连接工厂,确保连接的创建和关闭。
  • 注册消息监听器,并在接收到消息时调用相应的处理方法。
  • 支持基于频道和基于模式的发布/订阅模式。
  • 提供了灵活的配置选项,如消息转换器、错误处理器等。

总体而言,MessageListenerAdapterRedisMessageListenerContainer 是一对重要的组件,它们使得在 Spring 应用中实现 Redis 消息监听变得更加简单和灵活。

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

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

相关文章

java的内存分配和回收机制

Java 与 C之间有一堵由内存动态分配和垃圾收集技术所围成的高墙&#xff0c;墙外面的人想进去&#xff0c;墙里面的人却想出来。 概述 垃圾收集&#xff08;GC&#xff09;需要完成的三件事情&#xff1a; 哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&am…

Mybatis-plus进阶篇(一)

文章目录 一.条件构造器二.功能详解1. allEq使用范围方法签名:参数说明示例 一.条件构造器 MyBatis-Plus 提供了一套强大的条件构造器&#xff08;Wrapper&#xff09;&#xff0c;用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件&#xff0…

Linux操作系统入门(三)

_______________________________________________ 一.Linux操作系统的文件结构 相比于Windows操作系统的C,D,E等盘符&#xff0c;Linux操作系统仅有一个"/"符号的根目录. 这其中存在一个显著的不同&#xff0c;Linux操作系统使用的是斜杠"/",而Windows…

基于微信小程序的宠物之家的设计与实现

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的宠物之家/宠物综合…

集群聊天服务器项目【C++】(二)Json的简单使用

在上一章中&#xff0c;简单介绍了本项目的内容、技术栈、需求和目标等&#xff0c;详细介绍了环境配置&#xff0c;如果还没有配置成功&#xff0c;请参考我的上一篇博客环境配置 今天主要介绍Json库是什么以及简单的使用。 1.为什么要使用Json 我们在网络传输数据时&#…

判断当前环境是否为docker容器下

判断当前环境是否为docker容器下 webshell后或登录到系统后台&#xff0c;判断是否为docker容器可使用如下方法&#xff1a; 方式一&#xff1a;使用ls -alh命令查看是否存在.dockerenv来判断是否在docker容器环境内 ls -alh /.dockerenv如下图无.dockerenv文件&#xff0c;所…

本地部署轻量级web开发框架Flask结合内网穿透公网环境访问管理界面

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

无人机飞手教员组装、调试高级教学详解

随着无人机技术的飞速发展&#xff0c;其在航拍、农业、救援、监测等多个领域的应用日益广泛&#xff0c;对专业无人机飞手的需求也随之增加。作为无人机飞手教员&#xff0c;掌握无人机的高级组装、调试技能不仅是教学的基础&#xff0c;更是培养学生成为行业精英的关键。本教…

【吊打面试官系列-Redis面试题】使用过 Redis 做异步队列么,你是怎么用的?

大家好&#xff0c;我是锋哥。今天分享关于【使用过 Redis 做异步队列么&#xff0c;你是怎么用的&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 使用过 Redis 做异步队列么&#xff0c;你是怎么用的&#xff1f; 一般使用 list 结构作为队列&#xff0c;rpus…

Word中插入当前日期与时间

Word中插入当前日期与时间 通过构建基块的方法快速插入当前日期与时间 快捷键操作 快捷键具体功能说明 Alt Shift D 插入当前日期date Alt Shift T 插如当前时间time Ctrl Shift F9 使得域文本变为正常文本 Ctrl F11 锁定域更新域菜单工具会变为黑色 C…

你的大模型应用表现真的好吗?借助 Dify + Langfuse 一探究竟

背景介绍 众所周知&#xff0c;大模型应用的输出存在着一些不确定性&#xff0c;往往需要迭代多轮才能得到较为稳定的输出结果&#xff0c;因此开发者往往需要关注大模型应用的实际表现&#xff0c;并进行有针对性的优化。 然而常规 Web 服务的监控机制往往无法满足大模型应用…

python绘制3d建筑

import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d.art3d import Poly3DCollection# 随机生成建筑块数据 def generate_building_blocks(num_blocks, grid_size100, height_range(5, 50), base_size_range(10, 30)):buildings []for _ in range(…

sqli-labs靶场自动化利用工具——第1关

文章目录 概要整体架构流程技术细节执行效果小结 概要 Sqli-Labs靶场对于网安专业的学生或正在学习网安的朋友来说并不陌生&#xff0c;或者说已经很熟悉。那有没有朋友想过自己开发一个测试脚本能实现自动化化测试sqli-labs呢&#xff1f;可能有些人会说不是有sqlmap&#xf…

数据结构 | 栈和队列

文章目录 栈和队列1. 栈&#xff1a;后进先出&#xff08;LIFO&#xff09;的数据结构1.1 概念与结构1.2 栈的实现 2. 队列&#xff1a;先进先出&#xff08;FIFO&#xff09;的数据结构2.1 概念与结构2.2 队列的实现 3. 栈和队列算法题3.1 有效的括号3.2 用队列实现栈3.3 用栈…

回溯——13.解数独

力扣题目链接 编写一个程序&#xff0c;通过填充空格来解决数独问题。 一个数独的解法需遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 . 表示。 解题思路 …

中国矿业大学《2023年868+2007年自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《25届中国矿业大学868自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2007年复试真题 2023年初试真题 Part1&#xff1a;完整版真题 2007年复试真题 2…

Qt 定时器-定时备份

定时备份 在Qt 中&#xff0c;可以使用QTimer类来实现定时备份功能。以下是一个示例代码&#xff0c;每隔一段时间自动执行备份操作&#xff1a; #include <QTimer>QTimer timer; int backupInterval 24 * 60 * 60 * 1000;//备份间隔为24小时connect(&timer, &…

feign client发送Post请求,发送对象参数,服务端接收不到正确参数报错排查

记一次feignclient发送请求服务端接收不到正确参数排查 服务端代码&#xff1a; Operation(summary "Create team")PostMapping("post")RequiresPermissions("team:add")public RestResponse addTeam(Valid Team team) {this.teamService.crea…

Android应用性能优化

Android手机由于其本身的后台机制和硬件特点&#xff0c;性能上一直被诟病&#xff0c;所以软件开发者对软件本身的性能优化就显得尤为重要&#xff1b;本文将对Android开发过程中性能优化的各个方面做一个回顾与总结。 Cache优化 ListView缓存&#xff1a; ListView中有一个回…

SpringCloud(八)配置中心服务化和高可用

在前两篇的介绍中&#xff0c;客户端都是直接调用配置中心的server端来获取配置文件信息。这样就存在了一个问题&#xff0c;客户端和服务端的耦合性太高&#xff0c;如果server端要做集群&#xff0c;客户端只能通过原始的方式来路由&#xff0c;server端改变IP地址的时候&…