RabbitMQ安装配置,封装工具类,发送消息及监听
1. Get-Started
docker安装rabbitmq
- 拉取镜像
[root@heima ~]# docker pull rabbitmq:3.8-management
3.8-management: Pulling from library/rabbitmq
7b1a6ab2e44d: Pull complete
37f453d83d8f: Pull complete
e64e769bc4fd: Pull complete
c288a913222f: Pull complete
13adc5da62c6: Pull complete
bd67e639afcb: Pull complete
9a48b5ad2519: Pull complete
1cdfc59624be: Pull complete
8f5ad79f0ad6: Pull complete
Digest: sha256:543f7268600a27a39e2fdd532f8df479636fc0cf528aadde88d5fe718bed71e4
Status: Downloaded newer image for rabbitmq:3.8-management
docker.io/library/rabbitmq:3.8-management
- 创建目录
mkdir -p /home/apps/rabbitmq/data
- 运行容器
docker run \
-d \
--name rabbitmq \
--restart=always \
--privileged=true \
-p 5672:5672 \
-p 15672:15672 \
-v /home/apps/rabbitmq/data:/var/lib/rabbitmq \
-e RABBITMQ_DEFAULT_VHOST=vhost0 \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=admin123 \
rabbitmq:3.8-management
- 启用web界面管理插件
docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq_management
或
-- 进入容器
docker exec -it rabbitmq /bin/bash
-- 安装插件
rabbitmq-plugins enable rabbitmq_management
- 浏览器访问 http://虚拟机ip:15672/出现以下界面说明安装成功。
输入上面在初始化Rabbitmq容器时我们自己指定了默认账号和密码:admin/admin123,如果没有指定的话那么rabbitmq的默认账号密码是:guest/guest
扩展 :安装延迟队列
- 去官网下载插件(v3.8.17)
- 地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
# 将下载好的插件复制到mq容器内部
docker cp rabbitmq_delayed_message_exchange-3.8.17.8f537ac.ez rabbitmq:/plugins# 进入mq容器
docker exec -it rabbitmq /bin/bash# 开启插件支持
rabbitmq-plugins enable rabbitmq_delayed_message_exchange# 查看插件列表
rabbitmq-plugins list
2. 生产者模块
2.1 项目引入依赖:
rabbitmq依赖包,使用RabbitMq这2个依赖就够了。
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-amqp</artifactId><scope>provided</scope>
</dependency>
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><scope>provided</scope>
</dependency>
封装工具类用到的包
<!--hutool工具包-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.17</version>
</dependency>
2.2 工具类
- RabbitMqHelper
import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
public class RabbitMqHelper {public static final String REQUEST_ID_HEADER = "requestId";private final RabbitTemplate rabbitTemplate;private final MessagePostProcessor processor = new BasicIdMessageProcessor();private final ThreadPoolTaskExecutor executor;public RabbitMqHelper(RabbitTemplate rabbitTemplate) {this.rabbitTemplate = rabbitTemplate;executor = new ThreadPoolTaskExecutor();//配置核心线程数executor.setCorePoolSize(10);//配置最大线程数executor.setMaxPoolSize(15);//配置队列大小executor.setQueueCapacity(99999);//配置线程池中的线程的名称前缀executor.setThreadNamePrefix("mq-async-send-handler");// 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//执行初始化executor.initialize();}/*** 根据exchange和routingKey发送消息*/public <T> void send(String exchange, String routingKey, T t) {log.debug("准备发送消息,exchange:{}, RoutingKey:{}, message:{}", exchange, routingKey, t);// 1.设置消息标示,用于消息确认,消息发送失败直接抛出异常,交给调用者处理String id = UUID.randomUUID().toString(true);CorrelationData correlationData = new CorrelationData(id);// 2.设置发送超时时间为500毫秒rabbitTemplate.setReplyTimeout(500);// 3.发送消息,同时设置消息idrabbitTemplate.convertAndSend(exchange, routingKey, t, processor, correlationData);}/*** 根据exchange和routingKey发送消息,并且可以设置延迟时间*/public <T> void sendDelayMessage(String exchange, String routingKey, T t, Duration delay) {// 1.设置消息标示,用于消息确认,消息发送失败直接抛出异常,交给调用者处理String id = UUID.randomUUID().toString(true);CorrelationData correlationData = new CorrelationData(id);// 2.设置发送超时时间为500毫秒rabbitTemplate.setReplyTimeout(500);// 3.发送消息,同时设置消息idrabbitTemplate.convertAndSend(exchange, routingKey, t, new DelayedMessageProcessor(delay), correlationData);}/*** 根据exchange和routingKey 异步发送消息,并指定一个延迟时间** @param exchange 交换机* @param routingKey 路由KEY* @param t 数据* @param <T> 数据类型*/public <T> void sendAsync(String exchange, String routingKey, T t, Long time) {String requestId = MDC.get(REQUEST_ID_HEADER);CompletableFuture.runAsync(() -> {try {MDC.put(REQUEST_ID_HEADER, requestId);// 发送延迟消息if (time != null && time > 0) {sendDelayMessage(exchange, routingKey, t, Duration.ofMillis(time));} else {send(exchange, routingKey, t);}} catch (Exception e) {log.error("推送消息异常,t:{},", t, e);}}, executor);}/*** 根据exchange和routingKey 异步发送消息** @param exchange 交换机* @param routingKey 路由KEY* @param t 数据* @param <T> 数据类型*/public <T> void sendAsync(String exchange, String routingKey, T t) {sendAsync(exchange, routingKey, t, null);}
}
- MqConfig
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.MDC;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.ContainerCustomizer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;@Configuration
@ConditionalOnClass(value = {MessageConverter.class, AmqpTemplate.class})
public class MqConfig implements EnvironmentAware{public static final String REQUEST_ID_HEADER = "requestId";public static final String ERROR_EXCHANGE = "error.topic";public static final String ERROR_KEY_PREFIX = "error.";public static final String ERROR_QUEUE_TEMPLATE = "error.{}.queue";private String defaultErrorRoutingKey;private String defaultErrorQueue;@Bean(name = "rabbitListenerContainerFactory")@ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = "type", havingValue = "simple",matchIfMissing = true)SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,ObjectProvider<ContainerCustomizer<SimpleMessageListenerContainer>> simpleContainerCustomizer) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();configurer.configure(factory, connectionFactory);simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer);factory.setAfterReceivePostProcessors(message -> {Object header = message.getMessageProperties().getHeader(REQUEST_ID_HEADER);if(header != null) {MDC.put(REQUEST_ID_HEADER, header.toString());}return message;});return factory;}@Beanpublic MessageConverter messageConverter(ObjectMapper mapper){// 1.定义消息转换器Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(mapper);// 2.配置自动创建消息id,用于识别不同消息jackson2JsonMessageConverter.setCreateMessageIds(true);return jackson2JsonMessageConverter;}/*** <h1>消息处理失败的重试策略</h1>* 本地重试失败后,消息投递到专门的失败交换机和失败消息队列:error.queue*/@Bean@ConditionalOnClass(MessageRecoverer.class)@ConditionalOnMissingBeanpublic MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){// 消息处理失败后,发送到错误交换机:error.direct,RoutingKey默认是error.微服务名称return new RepublishMessageRecoverer(rabbitTemplate, ERROR_EXCHANGE, defaultErrorRoutingKey);}/*** rabbitmq发送工具**/@Bean@ConditionalOnMissingBean@ConditionalOnClass(RabbitTemplate.class)public RabbitMqHelper rabbitMqHelper(RabbitTemplate rabbitTemplate){return new RabbitMqHelper(rabbitTemplate);}/*** 专门接收处理失败的消息*/@Beanpublic DirectExchange errorMessageExchange(){return new DirectExchange(ERROR_EXCHANGE);}@Beanpublic Queue errorQueue(){return new Queue(defaultErrorQueue, true);}@Beanpublic Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with(defaultErrorRoutingKey);}@Overridepublic void setEnvironment(Environment environment) {String appName = environment.getProperty("spring.application.name");this.defaultErrorRoutingKey = ERROR_KEY_PREFIX + appName;this.defaultErrorQueue = StrUtil.format(ERROR_QUEUE_TEMPLATE, appName);}
}
- Processor
import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;public class BasicIdMessageProcessor implements MessagePostProcessor {public static final String REQUEST_ID_HEADER = "requestId";@Overridepublic Message postProcessMessage(Message message) throws AmqpException {String requestId = MDC.get(REQUEST_ID_HEADER);if (requestId == null) {requestId = UUID.randomUUID().toString(true);}// 写入RequestID标示message.getMessageProperties().setHeader(REQUEST_ID_HEADER, requestId);return message;}
}----------------------------------------------------------------------import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import java.time.Duration;public class DelayedMessageProcessor extends BasicIdMessageProcessor {private final long delay;public DelayedMessageProcessor(Duration delay) {this.delay = delay.toMillis();}@Overridepublic Message postProcessMessage(Message message) throws AmqpException {// 1.添加消息idsuper.postProcessMessage(message);// 2.添加延迟时间message.getMessageProperties().setHeader("x-delay", delay);return message;}
}
2.3 配置
通常mq是放在common模块中,别的模块需要mq时就引入该模块,因此需要把MqConfig放在IOC容器里加载。
- resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.tianji.common.autoconfigure.mq.MqConfig
配置rabbitmq的地址等信息
- boostrap.yml
spring:rabbitmq:host: ${mydemo.mq.host:192.168.150.101}port: ${mydemo.mq.port:5672}virtual-host: ${mydemo.mq.vhost:/vhost0}username: ${mydemo.mq.username:admin}password: ${mydemo.mq.password:admin123}listener:simple:retry:enabled: ${mydemo.mq.listener.retry.enable:true} # 开启消费者失败重试initial-interval: ${mydemo.mq.listener.retry.interval:1000ms} # 初始的失败等待时长为1秒multiplier: ${mydemo.mq.listener.retry.multiplier:2} # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: ${mydemo.mq.listener.retry.max-attempts:3} # 最大重试次数stateless: ${mydemo.mq.listener.retry.stateless:true} # true无状态;false有状态。如果业务中包含事务,这里改为false
2.4 测试文件
TestController
@RestController
public class TestController {@AutowiredRabbitMqHelper rabbitMqHelper;@GetMapping("/hello")public String hello(){return "hello";}@GetMapping("/sendMsg")public String sendMsg(){rabbitMqHelper.send("order.topic", // "order.topic""order.pay", // "order.pay"UserDto.builder().id(10001).name("gz").age(23).phone("15500000001").email("123@qq.com").build());return "success";}
}
UserDto
import lombok.Builder;
import lombok.Data;@Data
@Builder
public class UserDto {private Integer id;private String name;private String phone;private Integer age;private String email;
}
2.5 生产者测试
生产者模块目录结构
启动生产者服务,访问http://127.0.0.1:8080/sendMsg
报错了,原因是没有消费者消费消息
但是发现创建了新的错误消息exchange和queue
因此,接下来创建消费者监听消息。
3. 消费者
3.1 引入通用模块
由于消费者也需要使用刚刚的工具类和UserDto用来接收消息。
而这些工具类和UserDto都在模块rabbitmq-demo中。因此,在消费者模块中引入该生产者模块(如果这些通用的配置和实体类dto都在一个通用的模块common中,哪些模块需要发送消息,哪些模块需要监听消息,就都引入common模块就行了)
<groupId>com.gzdemo</groupId><artifactId>rabbitmq-demo</artifactId><version>1.0-SNAPSHOT</version>
因为rabbitmq-demo模块中已经引入了RabbitMq相关依赖,因此消费者模块不需要重复引入RabbitMq相关的依赖。只需要把依赖包添加到classpath下,再import就行了
3.2 配置yml
与生产者的配置相同,通常只有消费者才需要配置listener,生产者不需要。
3.3 编写listener
import com.gzdemo.rabbitmq.pojos.UserDto;import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class UserListener {/*** 监听消息*/@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "learning.lesson.pay.queue", durable = "true"),exchange = @Exchange(name = "order.topic", type = ExchangeTypes.TOPIC),key = "order.pay"))public void listenLessonPay(UserDto userDto){System.out.println(userDto);}
}
3.4 消费者目录结构
这里是随便找了个同工程中的子模块作为消费者测试,在UserListener类中监听消息
4 测试消息发送、监听
启动这两个服务,浏览器访问http://127.0.0.1:8080/sendMsg,多访问几次后发现消费者接收到了消息
生产者console
2024-06-14 05:46:39.187 INFO 106168 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [192.168.150.101:5672]
2024-06-14 05:46:39.210 INFO 106168 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#399d82:0/SimpleConnection@1673b17 [delegate=amqp://admin@192.168.150.101:5672/vhost0, localPort= 61317]
相关文章:

RabbitMQ安装配置,封装工具类,发送消息及监听
1. Get-Started docker安装rabbitmq 拉取镜像 [rootheima ~]# docker pull rabbitmq:3.8-management 3.8-management: Pulling from library/rabbitmq 7b1a6ab2e44d: Pull complete 37f453d83d8f: Pull complete e64e769bc4fd: Pull complete c288a913222f: Pull complet…...

iOS接入Flutter
在现有的iOS项目上接入Flutter,参考链接 第一步:创建flutter项目,即 创建 Flutter module flutter create --template module my_flutter第二步:创建framework,这里选择的是B方式,即 选项 B - 在 Xcode 中…...

【ubuntu】用户添加root权限
添加root用户添加新用户并赋予权限 文件只读,无法更改 rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# chmod -R 777 /etc/sudoers rootubuntu-server:/home/ubuntu# vi /et…...

设计通用灵活的LabVIEW自动测试系统
为了在不同客户案例中灵活使用不同设备(如采集卡、Modbus模块)且保持功能一致的LabVIEW自动测试系统,需要采用模块化的软件架构、配置文件管理、标准化接口和良好的升级维护策略。本文从软件架构、模块化设计、配置管理、升级维护、代码管理和…...

C# WinForm —— 35 StatusStrip 介绍
1. 简介 状态栏 StatusStrip,默认在软件的最下方,用于显示系统时间、版本、进度条、账号、角色信息、操作位置信息等 可以在状态栏中添加的控件类型有:StatusLabel、ProgressBar、DropDownButton、SplitButton 2. 属性 属性解释(Name)控…...

如何应对生活中的不确定性:仁者安仁,知者利仁。
有较高自尊水平的人,接近于孔子说的:仁者。 ——— 有着稳定的高自尊,无论外在环境如何变化,对其影响都不大,他能够愉快地生活。 相反:一个人处于低自尊状态,就会活得很痛苦,对自己…...

C#面:请解释C#接口的显式实现有什么意义
C#接口的显式实现是指在实现接口成员时,使用接口名称进行限定的方式。这种方式可以在一个类中实现多个接口,并且可以避免接口成员之间的命名冲突。显式实现接口的成员只能通过接口类型来访问,而不能通过类的实例来访问。 显式实现接口的主要…...

STM32项目分享:智能窗帘系统
目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: https://www.bilibili.c…...

【算法-力扣】72. 编辑距离(动态规划)
目录 一、题目描述 二、解题思路 三、参考答案 一、题目描述 编辑距离 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 示例 1&#…...

Spring 系统架构图
Spring 系统架构图 Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。 Spring Framework的发展也经历了很多版本的变更,每个版本都有相应的调整 Spring Framework的5版本目前没有最新的架构图,而最新的是4版本,…...

同三维T80005EHS-4K60 4K60 HDMI/SDI编码器
1路4K60 HDMI或12G SDI输入,2路3.5MM音频输入,对应HDMI或SDI,1个USB口和1个SD卡槽,可录像到U盘/移动硬盘/SSD硬盘/TF卡 产品简介: 同三维T80005EHS-4K60 4K60HDMI/SDI H.265编码器采用最新高效H.265高清数字视频压缩…...

React state(及组件) 的保留与重置
当在树中相同的位置渲染相同的组件时,React 会一直保留着组件的 state return (<div><Counter />{showB && <Counter />} </div> ) // 当 showB 为 false, 第二个计数器停止渲染,它的 state 完全消失了。这是因为 React…...

flask返回的数据怎么是转义后的字符串啊
Flask在返回JSON数据时,默认情况下会对特殊字符进行转义,以确保数据能安全地在HTML页面中展示,避免XSS(跨站脚本攻击)等安全问题。如果不希望Flask对JSON响应中的字符串自动转义,通常是因为你希望在前端直接使用这些数据(例如作为JavaScript的一部分),那么需要确保数据…...

C++17并行算法与HIPSTDPAR
C17 parallel algorithms and HIPSTDPAR — ROCm Blogs (amd.com) C17标准在原有的C标准库中引入了并行算法的概念。像std::transform这样的并行版本算法保持了与常规串行版本相同的签名,只是增加了一个额外的参数来指定使用的执行策略。这种灵活性使得已经使用C标准…...

【什么是几度cms,主要功能有什么】
几度CMS内容管理框架是基于 PHP 语言采用最新 Thinkphp 作为开发框架生产的网站 内容管理框架,提供“电脑网站 手机网站 多终端 APP 接口”一体化网站技术解 决方案。她拥有强大稳定底层框架,以灵活扩展为主的开发理念,二次开发方便且…...

组合和外观模式
文章目录 组合模式1.引出组合模式1.院系展示需求2.组合模式基本介绍3.组合模式原理类图4.解决的问题 2.组合模式解决院系展示1.类图2.代码实现1.AbsOrganizationComponent.java 总体抽象类用于存储信息和定义方法2.University.java 第一层,University 可以管理 Coll…...

设置服务器禁止和ip通信
要禁止服务器与特定 IP 地址的通信,可以使用防火墙来设置规则。在 Ubuntu 上,iptables 是一个常用的防火墙工具。以下是使用 iptables 设置禁止与特定 IP 通信的步骤: 阻止所有进出的通信 如果你想阻止服务器与特定 IP 地址的所有通信&…...

中文技术文档的写作规范(搬运)
阮一峰老师的《中文技术文档的写作规范》搬运。 链接指路: https://github.com/ruanyf/document-style-guide/tree/master 内容:对中文技术文档从标题、文本、段落、数值、标点符号、文档体系、参考链接等七大方面进行了简明扼要的介绍。...

「实战应用」如何用DHTMLX将上下文菜单集成到JavaScript甘特图中(一)
DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求,是最完善的甘特图图表库。 DHTMLX Gantt是一个高度可定制的工具,可以与项目管理应用程序所需的其他功能相补充。在本文中您将学习如何使用自定义上…...

Python使用策略模式生成TCP数据包
使用策略模式(Strategy Pattern)来灵活地生成不同类型的TCP数据包。 包括三次握手、数据传输和四次挥手。 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethodclass TcpPacketStrategy(A…...

无文件落地分离拆分-将shellcode从文本中提取-file
马子分为shellcode和执行代码. --将shellcode单独拿出,放在txt中---等待被读取执行 1-cs生成python的payload. 2-将shellcode进行base64编码 import base64code b en_code base64.b64encode(code) print(en_code) 3-将编码后的shellcode放入文件内 4-读取shellcod…...

MySQL 日志(一)
本篇主要介绍MySQL日志的相关内容。 目录 一、日志简介 常用日志 一般查询日志和慢查询日志的输出形式 日志表 二、一般查询日志 三、慢查询日志 四、错误日志 一、日志简介 常用日志 在MySQL中常用的日志主要有如下几种: 这些日志通常情况下都是关闭的&a…...

XML 编辑器:功能、选择与使用技巧
XML 编辑器:功能、选择与使用技巧 简介 XML(可扩展标记语言)是一种用于存储和传输数据的标记语言。由于其灵活性和广泛的应用,XML编辑器成为开发者、数据管理者和内容创作者的重要工具。本文将探讨XML编辑器的功能、选择标准以及…...

单例模式(设计模式)
文章目录 概述1. 饿汉式(hungry Initialization)2. 懒汉式(Lazy Initialization)3.双重检查锁定(Double-Checked Locking)4. 静态内部类(Static Inner Class)5. 枚举(Enu…...

提升你的编程体验:自定义 PyCharm 背景图片
首先,打开 PyCharm 的设置菜单,点击菜单栏中的 File > Settings 来访问设置,也可以通过快捷键 CtrlAItS 打开设置。 然后点击Appearance & Behavior > Appearance。 找到Background image...左键双击进入。 Image:传入自己需要设置…...

SpringCloud与Dubbo区别?
相同点: dubbo与springcloud都可以实现RPC远程调用。 dubbo与springcloud都可以使用分布式、微服务场景下。 区别: dubbo有比较强的背景,在国内有一定影响力。 dubbo使用zk或redis作为作为注册中心 springcloud使用eureka作为注册中心 dubbo支持多种协议,默认使用…...

简单Mesh多线程合并,使用什么库性能更高
1)简单Mesh多线程合并,使用什么库性能更高 2)Unity Semaphore.WaitForSignal耗时高 3)VS编辑的C#代码注释的中文部分乱码 4)变量IntPtr m_cachePtr切换线程后变空 这是第389篇UWA技术知识分享的推送,精选了…...

长亭培训加复习安全产品类别
下面这个很重要参加hw时要问你用的安全产品就有这个 检测类型产品 偏审计 安全防御类型 EDR类似于杀毒软件 安全评估 任何东西都要经过这个机械勘察才能上线 安全管理平台 比较杂 比较集成 审计 漏扫 评估 合在这一个平台 也有可能只是管理 主机理解为一个电脑 安了终端插件…...

memcached介绍和详解
Memcached 是一种高性能、分布式内存缓存系统,常用于加速动态 web 应用程序的性能,通过缓存数据库查询结果、对象等数据,减少对数据库的访问压力,从而提高响应速度和系统吞吐量。 ### Memcached 的特点和工作原理 #### 特点 1. …...

Spring boot 注解实现幂等性
1. 添加 Spring AOP 依赖 在 pom.xml 中添加如下依赖: <dependencies><!-- Spring AOP dependency --><dependency><groupIdorg.springframework.boot</groupId><artifactIdspring-boot-starter-aop</artifactId></depend…...