SpringBoot 集成 RabbitMQ

news2025/1/17 21:59:41

SpringBoot 集成 RabbitMQ

1.应用实例

  • 需求说明/图解

image-20230302221224596

-P : 消息的发送者/生产者
-C : 消息的接受者/消费者

-中间表示队列

image-20230302222158980

  • 完成步骤
  1. 添加依赖
<!--rabbitmq-需要的 AMQP 依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  1. 修改yaml配置
spring:
  #rabbitmq 配置
  rabbitmq:
    host: 192.168.79.202
    username: guest
    password: guest
    #虚拟主机
    virtual-host: /
    #端口
    port: 5672
    listener:
      simple:
        #消费者最小数量
        concurrency: 10
        #消费者最大数量
        max-concurrency: 10
        #限制消费者,每次只能处理一条消息,处理完才能继续下一条消息
        prefetch: 1
        #启动时是否默认启动容器,默认为 true
        auto-startup: true
        #被拒绝时重新进入队列的
        default-requeue-rejected: true
    template:
      retry:
        #启用消息重试机制,默认为 false
        enabled: true
        #初始重试间隔时间
        initial-interval: 1000ms
        #重试最大次数,默认为 3 次
        max-attempts: 3
        #重试最大时间间隔,默认 10000ms
        max-interval: 10000ms
        #重试的间隔乘数,
        #配置 2 的话,第一次等 1s,第二次等 2s,第三次等 4s
        multiplier: 1

        #在 RabbitMQ 中,initial-interval 和 max-interval 是用于指定消息重试机制的两个参数,
        #它们的区别如下:
        #1. initial-interval(初始间隔时间):表示第一次重试的时间间隔,也就是在消息第一次处
        #理失败后,等待多长时间再尝试重新发送消息。这个参数的默认值是 1 秒。
        #2.max-interval(最大间隔时间):表示重试过程中的最大时间间隔,也就是每次重试时,
        #最长等待多长时间再尝试重新发送消息。这个参数的默认值是 10 秒。
  1. 在RabbitMQ配置类中创建队列
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    //定义队列名
    private static final String QUEUE = "queue";

	//创建队列
    /**
     * 1. 配置队列
     * 2. 队列名为 queue
     * 3. true 表示: 持久化 (不填,默认为true,默认持久化)
     * durable: 队列是否持久化。 队列默认是存放到内存中的,rabbitmq 重启则丢失,
     * 若想重启之后还存在则队列要持久化,
     * 保存到 Erlang 自带的 Mnesia 数据库中,当 rabbitmq 重启之后会读取该数据库
     * @return
     */
    @Bean
    public Queue queue(){
        return new Queue(QUEUE,true);
    }
    
}

  1. 创建消息发送者
/**
 * 消息发送者
 */
@Slf4j
@Service
public class MQSender {

    @Resource
    private RabbitTemplate rabbitTemplate;

    //方法:发送消息
    public void send(Object msg){
        log.info("发送消息-" + msg);
        //没有指定交换机会走默认的交换机,AMQP default
        //AMQP default是一个direct路由模式的交换机
        rabbitTemplate.convertAndSend("queue",msg);
    }

}
  1. 创建消息接收者
/**
 * 消息接收者
 */
@Service
@Slf4j
public class MQReceiver {

    //方法:接收消息
    @RabbitListener(queues = "queue")
    public void receive(Object msg) {
        log.info("接收到消息--" + msg);
    }

}
  1. 创建controller进行测试
@Controller
public class RabbitMQHandler {

    //装配MQSender
    @Resource
    private MQSender mqSender;

    //方法:调用消息生产者,发送消息
    @RequestMapping("/mq")
    @ResponseBody
    public void mq(){
        mqSender.send("hello llp");
    }
}

2.完成测试

  1. 配置 RabbitMQ 所在的 Linux, 开放 5672 端口, 因为 Java 访问 RabbitMQ, 走的是 5672测试前,将 Mysql, Redis,RabbitMQ 启动。
  • 防火墙开启端口访问
firewall-cmd --zone=public --add-port=5672/tcp --permanent
  • 开启后需要重启防火墙才生效
firewall-cmd --reload
  • 执行 firewall-cmd --list-ports 查看端口
  1. 启动项目, 再观察 RabbitMQ 管控台

image-20230303212547071

image-20230303212600198

image-20230303212611028

image-20230303212619416

image-20230303212629191

观察后端输出

image-20230303212258586

image-20230303212716747

image-20230303212727482

当前案例, 走的是默认交换机 (AMQP Default)

image-20230303212811691

RabbitMQ 使用模式

1. Fanout-广播模式

Fanout简介

  1. fanout 就是广播模式, 就是把交换机(Exchange)里的消息发送给所有绑定该交换机的
    队列,忽略 routingKey(也就是路由)。

  2. 示意图

image-20230303202028717

解读上图:

  • 生产者把消息发送给指定的交换机
  • 再把交换机的消息发送给所有绑定该交换机的队列, 忽略 routingKey/路由
  1. 官方文档: https://www.rabbitmq.com/tutorials/tutorial-three-java.html

image-20230303202159064

应用实例

  • 需求说明/图解

image-20230303202229580

  • 执行效果

image-20230303210901823

代码实现

添加队列和交换机,绑定队列和交换机

@Configuration
public class RabbitMQConfig {
    
    private static final String QUEUE1 = "queue_fanout01";
    private static final String QUEUE2 = "queue_fanout02";
    private static final String EXCHANGE = "fanoutExchange";

     //--------fanout广播模式---------
   /**
     * 1. 配置队列
     * 2. 队列名为 queue
     * 3. true 表示: 持久化 (不填,默认为true,默认持久化)
     * durable: 队列是否持久化。 队列默认是存放到内存中的,rabbitmq 重启则丢失,
     * 若想重启之后还存在则队列要持久化,
     * 保存到 Erlang 自带的 Mnesia 数据库中,当 rabbitmq 重启之后会读取该数据库
     * @return
     */
    @Bean
    public Queue queue1(){
        return new Queue(QUEUE1);
    }
    
    
    @Bean
    public Queue queue2(){
        return new Queue(QUEUE2);
    }

    //创建交换机
    @Bean
    public FanoutExchange exchange(){
        return new FanoutExchange(EXCHANGE);
    }

    //将队列和交换机进行绑定
    @Bean
    public Binding binding01(){
        //将队列queue1和交换机进行绑定
        return BindingBuilder.bind(queue1()).to(exchange());
    }

    @Bean
    public Binding binding02(){
        //将队列queue1和交换机进行绑定
        return BindingBuilder.bind(queue2()).to(exchange());
    }
}

消息发送者

/**
 * 消息发送者
 */
@Slf4j
@Service
public class MQSender {

    @Resource
    private RabbitTemplate rabbitTemplate;

    //fanout广播模式发送消息
    public void sendFanout(Object msg){
        log.info("发送消息-" + msg);
        //因为是fanout广播模式,不需要指定路由,这里路由赋空值处理
        rabbitTemplate.convertAndSend("fanoutExchange","",msg);
    }

}

消息接收者

/**
 * 消息接收者
 */
@Service
@Slf4j
public class MQReceiver {
	
    //queues对应接收消息的队列
    @RabbitListener	(queues = "queue_fanout01")
    public void receive1(Object msg) {
        log.info("从 queue_fanout01 接收消息-" + msg);
    }

    @RabbitListener(queues = "queue_fanout02")
    public void receive2(Object msg){
        log.info("从 queue_fanout02 接收消息-" + msg);
    }

}

controller层测试类

@Controller
public class RabbitMQHandler {

    //装配MQSender
    @Resource
    private MQSender mqSender;

    //调用消息生产者,发送消息到交换机
    @RequestMapping("/mq/fanout")
    @ResponseBody
    public void fanout(){
        mqSender.sendFanout("hello fanout~");
    }

}

完成测试

image-20230303213503564

  • 点击交换机 fanoutExchange, 查看绑定情况

image-20230303213716620

image-20230303213802275

image-20230303213816463

观察后台输出

image-20230303213840168

点击队列名,查看队列情况

image-20230303213847891

image-20230303213901556

image-20230303213941410

2.Direct-路由模式

Direct简介

  1. direct 就是路由模式, 路由模式是在使用交换机的同时,生产者指定路由发送数据,
    消费者绑定路由接受数据。
  2. 与广播模式不同的是,广播模式只要是绑定了交换机的队列都会收到生产者向交换
    机推送过来的数据。而路由模式下加了一个路由设置,生产者向交换机发送数据时,会
    声明发送给交换机下的哪个路由,并且只有当消费者的队列绑定了交换机并且声明了路
    由,才会收到数据
  3. 示意图

image-20230303214433190

  • P:消息的生产者
  • X:交换机
  • 红色:队列
  • C1,C2:消息消费者
  • error,info,warning:路由
  1. 官方文档: https://www.rabbitmq.com/tutorials/tutorial-four-java.html

image-20230303214550619

应用实例

  • 需求说明/图解

image-20230303214622009

  • 执行效果

image-20230304102154461

代码实现

声明队列、交换机、路由

@Configuration
public class RabbitMQConfig {

    //direct
    private static final String QUEUE_DIRECT1 = "queue_direct01";
    private static final String QUEUE_DIRECT2 = "queue_direct02";
    private static final String EXCHANGE_DIRECT = "directExchange";
    //路由
    private static final String routing_key01 = "queue.red";
    private static final String routing_key02 = "queue.green";


    //--------direct路由模式---------
    @Bean
    public Queue queue_direct1() {
        return new Queue(QUEUE_DIRECT1);
    }

    @Bean
    public Queue queue_direct2() {
        return new Queue(QUEUE_DIRECT2);
    }

    @Bean
    public DirectExchange exchange_direct() {
        return new DirectExchange(EXCHANGE_DIRECT);
    }

    @Bean
    public Binding binding_direct1() {
        //将队列queue_direct1和交换机进行绑定,并给队列绑定路由
        return BindingBuilder.bind(queue_direct1()).to(exchange_direct()).with(routing_key01);
    }

    @Bean
    public Binding binding_direct2() {
        //将队列queue_direct2和交换机进行绑定,并给队列绑定路由
        return BindingBuilder.bind(queue_direct2()).to(exchange_direct()).with(routing_key02);
    }

}

消息发送者

/**
 * 消息发送者
 */
@Slf4j
@Service
public class MQSender {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void sendDirect1(Object msg){
        log.info("发送消息-" + msg);
        rabbitTemplate.convertAndSend("directExchange","queue.red",msg);
    }

    public void sendDirect2(Object msg){
        log.info("发送消息-" + msg);
        rabbitTemplate.convertAndSend("directExchange","queue.green",msg);
    }
    
}

消息接收者

/**
 * 消息接收者
 */
@Service
@Slf4j
public class MQReceiver {
    @RabbitListener(queues = "queue_direct01")
    public void queue_direct1(Object msg){
        log.info("从 queue_direct1 接收消息-" + msg);
    }

    @RabbitListener(queues = "queue_direct02")
    public void queue_direct2(Object msg){
        log.info("从 queue_direct2 接收消息-" + msg);
    }

}

controller测试

@Controller
public class RabbitMQHandler {

    //装配MQSender
    @Resource
    private MQSender mqSender;

    //direct 模式
    @GetMapping("/mq/direct01")
    @ResponseBody
    public void direct01() {
        mqSender.sendDirect1("hello aimee");
    }

    //direct 模式
    @GetMapping("/mq/direct02")
    @ResponseBody
    public void direct02() {
        mqSender.sendDirect2("hello llp");
    }
}

完成测试

  1. 启动项目, 再观察 RabbitMQ 管控台

    image-20230304102219589

    点击交换机 directExchange, 查看绑定情况

image-20230304102255218

image-20230304102303323

image-20230304102330002

image-20230304102335880

查看控制台数据情况

image-20230304102351213

点击相应的队列, 观察队列已经有了消息变化, (提示:发送消息后就观察, 因为是实时刷新
的)

image-20230304102522115

image-20230304102530547

image-20230304102537236

3.Topic主题模式

Topic 介绍

  1. direct 模式会造成路由 RoutingKey 太多, 而实际开发中往往是按照某个规则来进行路
    由匹配的, RabbitMQ 提供了 Topic 模式/主题模式来适应这种需求.
  2. Topic 模式是 direct 模式上的一种扩展/叠加, 扩展/叠加了模糊路由 RoutingKey 的模
    式, 可以理解为是模糊的路由匹配模式
  • *(星号):可以(只能)匹配一个单词

  • #(井号):可以匹配多个单词(或者零个)

示意图:

image-20230304102751872

  1. 官方文档: https://www.rabbitmq.com/tutorials/tutorial-five-java.html

image-20230304102839581

应用实例

  • 需求说明/图解

image-20230304102911668

  • 执行效果

代码实现

配置队列、交换机、路由

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQTopicConfig {

    //topic主题模式
    private static final String QUEUE_TOPIC1 = "queue_topic01";
    private static final String QUEUE_TOPIC2 = "queue_topic02";
    private static final String EXCHANGE_TOPIC = "topicExchange";
    //路由
    private static final String routing_key01 = "#.queue.#";
    private static final String routing_key02 = "*.queue.#";


    @Bean
    public Queue queue_topic01() {
        return new Queue(QUEUE_TOPIC1);
    }

    @Bean
    public Queue queue_topic02() {
        return new Queue(QUEUE_TOPIC2);
    }

    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange(EXCHANGE_TOPIC);
    }

    @Bean
    public Binding binding_topic1() {
        //将队列queue1和交换机进行绑定
        return BindingBuilder.bind(queue_topic01()).to(topicExchange()).with(routing_key01);
    }

    @Bean
    public Binding binding_topic2() {
        //将队列queue1和交换机进行绑定
        return BindingBuilder.bind(queue_topic02()).to(topicExchange()).with(routing_key02);
    }

}

消息发送者

/**
 * 消息发送者
 */
@Slf4j
@Service
public class MQSender {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void sendTopic1(Object msg) {
        log.info("发送消息-" + msg);
        rabbitTemplate.convertAndSend("topicExchange", "queue.red.message", msg);
    }

    public void sendTopic2(Object msg) {
        log.info("发送消息-" + msg);
        rabbitTemplate.convertAndSend("topicExchange", "green.queue.green.message", msg);
    }

}

消息接收者

/**
 * 消息接收者
 */
@Service
@Slf4j
public class MQReceiver {
-
    @RabbitListener(queues = "queue_topic01")
    public void queue_topic1(Object msg) {
        log.info("从 queue_topic01 接收消息-" + msg);
    }

    @RabbitListener(queues = "queue_topic02")
    public void queue_topic2(Object msg) {
        log.info("从 queue_topic02 接收消息-" + msg);
    }
}

编写controller层测试方法

@Controller
public class RabbitMQHandler {

    //装配MQSender
    @Resource
    private MQSender mqSender;

    //topic 模式
    @GetMapping("/mq/topic01")
    @ResponseBody
    public void topic01() {
        mqSender.sendDirect1("hello aimee topic");
    }

    //topic 模式
    @GetMapping("/mq/topic02")
    @ResponseBody
    public void topic02() {
        mqSender.sendDirect2("hello llp topic");
    }

}

完成测试

  1. 启动项目, 再观察 RabbitMQ 管控台

image-20230304112241248

点击交换机 topicExchange, 查看绑定情况

image-20230304112257946

image-20230304112310949

image-20230304112323341

观察后台输出

queue.red.message
green.queue.green.message
#.queue.#
*.queue.#
调用topic1, queue.red.message匹配到的路由是#.queue.#
调用topic2, green.queue.green.message匹配到的路由是*.queue.#和#.queue.#
* 有且仅有一个 
# 可以有多个也可以没有

image-20230304112228196

4.Headers模式

Headers 介绍

  1. headers 模式/headers 头路由模式 使用比较少
  2. headers 交换机是一种比较复杂且少见的交换机,不同于 direct 和 topic,它不关心路由 key 是否匹配,而只关心 header 中的 key-value 对是否匹配(这里的匹配为精确匹配,包含键和值都必须匹配), 有点类似于 http 中的请求头。
  3. headers 头路由模型中,消息是根据 prop 即请求头中 key-value 来匹配的。
  4. 绑定的队列(也可以理解成消费方) 指定的 headers 中必须包含一个"x-match"的键
  5. 键"x-match"的值有 2 个:all 和 any。
    all:表示绑定的队列/消费方 指定的所有 key-value 都必须在消息 header 中出现并匹配
    any:表示绑定的队列/消费方 指定的 key-value 至少有一个在消息 header 中出现并匹配即可

应用实例

  • 需求说明/图解
  1. 给 headers 交换机发送消息 hello ABC, 让 QUEUE01 和 QUEUE02 两个队列都接收
  2. 给 headers 交换机发送消息 hello llp, 让 QUEUE01 队列都接收
  3. 适应 headers 模式完成

代码实现

创建队列、交换机

@Configuration
public class RabbitMQHeadersConfig {

    private static final String QUEUE01 = "queue_header01";
    private static final String QUEUE02 = "queue_header02";
    private static final String EXCHANGE = "headersExchange";


    @Bean
    public Queue queue_header01() {
        return new Queue(QUEUE01);
    }

    @Bean
    public Queue queue_header02() {
        return new Queue(QUEUE02);
    }

    @Bean
    public HeadersExchange headersExchange() {
        return new HeadersExchange(EXCHANGE);
    }

    @Bean
    public Binding binding_header01() {
        Map<String,Object> map = new HashMap<>();
        map.put("color","red");
        map.put("speed","low");
        System.out.println("yy=" + headersExchange().hashCode());
        //whereAny(map): 只要发送的消息的属性 MessageProperties 有任意一个k-v匹配就 OK
        return BindingBuilder.bind(queue_header01()).to(headersExchange()).whereAny(map).match();
    }

    @Bean
    public Binding binding_header02() {
        Map<String, Object> map = new HashMap<>();
        map.put("color", "red");
        map.put("speed", "fast");
        System.out.println("xx=" + headersExchange().hashCode());
        //whereAll(map): 发送的消息的属性 MessageProperties 要全部匹配才 OK
        return BindingBuilder.bind(queue_header02()).to(headersExchange()).whereAll(map).match();
    }

}

消息发送者

@Slf4j
@Service
public class MQSender {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void sendHeader1(String msg) {
        MessageProperties properties = new MessageProperties();
        properties.setHeader("color", "red");
        properties.setHeader("speed", "fast");
        Message message = new Message(msg.getBytes(), properties);
        rabbitTemplate.convertAndSend("headersExchange","",message);
    }

    public void sendHeader2(String msg) {
        MessageProperties properties = new MessageProperties();
        properties.setHeader("color", "red");
        properties.setHeader("speed", "normal");
        Message message = new Message(msg.getBytes(), properties);
        rabbitTemplate.convertAndSend("headersExchange","",message);
    }

}

消息接收者

/**
 * 消息接收者
 */
@Service
@Slf4j
public class MQReceiver {

    @RabbitListener(queues = "queue_header01")
    public void queue_header1(Message message) {
        log.info("queue_header01 接收消息 message 对象" + message);
        log.info("queue_header01 接收消息" + new String(message.getBody()));
    }

    @RabbitListener(queues = "queue_header02")
    public void queue_header2(Message message) {
        log.info("queue_header2 接收消息 message 对象" + message);
        log.info("queue_header2 接收消息" + new String(message.getBody()));
    }
}

完成测试

  1. 启动项目, 再观察 RabbitMQ 管控台

image-20230304143653007

点击交换机 headersExchange, 查看绑定情况

image-20230304143711829

image-20230304143723498

image-20230304143730141

调用header1,队列1和队列2都能接收

image-20230304143756756

image-20230304143740916

调用header2,header头并不完全匹配,因此只有队列1能够接收到消息

image-20230304144022018

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

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

相关文章

python判断控制语句和输出练习

作业2&#xff1a;判断一个数&#xff0c;是否是2的指数 2的指数 0000 0010 0000 0001 0000 0100 0000 0011 0000 1000 0000 0111 0001 0000 0000 1111 提示&#xff1a;所有2的指数&#xff1a;n&(n - 1) 0 作业3&#xff…

【spring】spring5特性

1、整个 Spring5 框架的代码基于 Java8&#xff0c;运行时兼容 JDK9&#xff0c;许多不建议使用的类和方 法在代码库中删除 日志框架 2、Spring 5.0 框架自带了通用的日志封装 &#xff08;1&#xff09;Spring5 已经移除 Log4jConfigListener&#xff0c;官方建议使用 Log4j…

Linux23 --- 三次握手四次挥手、客户端编程流程代码、命令netstat、 tcp协议是个面向链接的可靠的流式服务

tcp协议特点&#xff1a; 面向连接的&#xff0c;可靠的&#xff0c;流式服务。 一、三次握手 、四次挥手 链接的建立通过三次握手&#xff0c;链接的断开通过四次挥手 1、TCP固定头部结构 2、三次握手 3、四次挥手 二、命令 - netstat -natp n - 用数字来表示ip地址、端口…

【8】【用户操作日志】操作日志SpringBootStarter

操作日志 此版本操作日志主要就是通过AOP拦截器实现的&#xff0c;整体主要分为AOP拦截器、自定义函数、日志上下文、扩展接口&#xff1b;组件提供了6个扩展点&#xff0c;自定义函数、日志上下文、用户信息获取&#xff0c;日志保存&#xff0c;自定义异常获取&#xff0c;入…

2023王道考研数据结构笔记第四章串

第四章 串 4.1 串的定义 4.1.1 串的相关概念 串&#xff1a;即字符串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列。一般记为S‘a1a2…an’ (n>0) 其中S是串名&#xff0c;单引号&#xff08;注&#xff1a;有的地方用双引号&#xff0c;如Java、C&am…

4. Unity之文件资源和其它杂项

1. 资源文件 unity中的Assets文件夹下的文件都可以称为时资源文件&#xff0c;包括模型文件、材质文件、纹理贴图文件、脚本文件、音频文件等&#xff0c;如果想查看某一个文件在电脑中的保存路径&#xff0c;可以选中指定文件后&#xff0c;单击鼠标右键选择show in Explorer…

研究生退税的详细流程

本文介绍在个人所得税软件中&#xff0c;进行退税操作的详细流程。 又到了一年一度的退税时间了。作为研究生&#xff0c;由于每个月都有固定的工资&#xff0c;有时还会有导师发放的补助、国家或院校等发放的奖学金等收入&#xff0c;所以其中有时需要缴纳一部分税款&#xff…

vue-template-admin的keep-alive缓存与移除缓存

一&#xff0c;场景 A页面是表单页面&#xff0c;填写后需要跳转B页面。如果B页面不操作返回的话&#xff0c;应该能还原A页面的内容&#xff0c;而如果B页面点击提交&#xff0c;再回到A页面的时候&#xff0c;应该清除缓存。 二&#xff0c;实现方法 A页面要缓存数据&…

网络互连模型:OSI 七层模型

OSI 七层模型 七层模型&#xff0c;亦称 OSI&#xff08;Open System Interconnection&#xff09;。OSI 七层参考模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间网络互联的标准体系&#xff0c;一般称为 OSI 参考模型或七层模型。OSI 七层…

询问new bing关于android开发的15个问题(前景、未来、发展方向)

前言&#xff1a;new bing是基于chat-gpt的新搜索工具&#xff0c;可以采用对话方式进行问题搜索&#xff0c;经过排队等候终于可以使用new bing&#xff0c;询问了目前我最关心的关于android开发几个问题 文章目录1.如何学好android开发&#xff1f;2.android开发能做什么?3.…

最近爆火的ChatGPT核心技术演进历程

文章目录1.前言2.初识ChatGPT2.1.什么是ChatGPT2.2.ChatGPT和其他模型对比具有的特性3.ChatGPT技术演进历程3.1.Transformer&#xff08;转移学习&#xff09;和基础模型3.2.GPT-1&#xff1a;简化模型&#xff0c;使其更适合自然语言生成3.2.1.什么是GPT-13.2.1.GPT-1的优势3.…

3.crypto-config.yaml配置文件分析和cryptogen工具使用[fabric2.2]

在fabric网络启动的过程中&#xff0c;会使用使用cryptogen 工具创建组织的证书文件&#xff0c;这时候就会用到crypto-config.yaml配置文件&#xff0c;例如fabric官方测试例程test-network中就用到了crypto-config-org1.yaml&#xff0c;crypto-config-org2.yaml&#xff0c;…

java实例解析类图中【关联、组合和聚合】的区别

总目录链接==>> AutoSAR入门和实战系列总目录 文章目录 聚合Composition聚合与组合的区别关联是两个独立类之间的关系,它通过它们的对象建立关联。关联可以是一对一、一对多、多对一、多对多。在面向对象的编程中,一个对象与另一个对象通信以使用该对象提供的功能和服…

轮盘赌选择法

轮盘赌选择原理 轮盘赌选择法&#xff08;roulette wheel selection&#xff09;是最简单也是最常用的选择方法&#xff0c;在该方法中&#xff0c;各个个体的选择概率和其适应度值成比例&#xff0c;适应度越大&#xff0c;选中概率也越大。 从图中可以看出一等奖、二等奖、…

Rust学习总结之数组,元组,结构体用法

学过数据结构的都知道有这么一个公式&#xff0c;程序数据结构算法&#xff0c;好的数据结构能大大降低算法设计的复杂度&#xff0c;也能更好的为算法服务。了解一门新的计算机编程语言其数据结构是必须首先要学的&#xff0c;这有利于对该语言的理解和快速上手。本文将对Rust…

vue引入cdn Vue 优化Vue引入 cdn vue cdn Vue优化引入CDN vue 项目 CDN优化

vue引入cdn Vue 优化Vue引入 cdn vue cdn Vue优化引入CDN vue 项目 CDN优化未引入 CDN前 main.js更改CDN方式引入在 vue.config 中引入 CDNindex.html 加载 cdn资源使用CDN引入资源后的main.js如果引入CDN后 组件不生效CDN 服务商推荐未引入 CDN前 main.js // 依赖使用 npm 方…

Windows server 2003怎么安装iis?Windows server 2003安装IIS教程

Windows 2008系统服务器安装IIS之前已经分享过了&#xff0c;和Windows 2003完全不同&#xff0c;今天飞飞将详细地和你分享Windows server 2003卸载和安装IIS的步骤方法&#xff0c;希望可以帮助到你~ 1、首先进入服务器&#xff0c;确定下服务器是否有安装IIS&#xff0c;有…

漫谈数据库表设计及索引设计

一.数据库表设计 在数据库表设计上有个很重要的设计准则&#xff0c;称为范式设计。 什么是范式设计&#xff1f; 范式来自英文Normal Form&#xff0c;简称NF。MySQL是关系型数据库&#xff0c;但是要想设计—个好的关系&#xff0c;必须使关系满足一定的约束条件&#xff0c…

论如何用C语言的数组手撕一棵特殊的完全二叉树----堆

目录 0.前言 1. 用数组表示存储一棵完全二叉树 2. 数组表示的完全二叉树的性质 3. 堆的基本概念 3.1 堆的核心性质 3.2 堆顶的性质 3.3 堆的单支性质 3.4 堆的左右支关系 4. 用代码实现堆 4.1 堆类的实现 4.2 堆的初始化 4.3 堆的销毁 4.4 获取堆顶的数据 4.5 …

这款 Python 工具进行数据分析及数据可视化真的很棒啊

前言 大家好&#xff0c;今天我们以全国各地区衣食住行消费数据为例&#xff0c;来分析2022年中国统计年鉴数据&#xff0c;统计全国各地人民的消费地图&#xff0c;看看&#xff1a; 哪个省份的人最能花钱 哪个省份的人最舍得花钱 哪个省份的人最抠门 全国各地区人民在吃、穿…