SpringCloud-consul

SpringCloud-consul


(尚硅谷Cloud学习笔记总结)

1. consul介绍

在这里插入图片描述

1.1 为什么要引入服务注册中心?

微服务所在的IP地址和端口号硬编码到订单微服务中,会存在非常多的问题
在这里插入图片描述

(1)如果订单微服务和支付微服务的IP地址或者端口号发生了变化,则支付微服务将变得不可用,需要同步修改订单微服务中调用支付微服务的IP地址和端口号。
(2)如果系统中提供了多个订单微服务和支付微服务,则无法实现微服务的负载均衡功能。
(3)如果系统需要支持更高的并发,需要部署更多的订单微服务和支付微服务,硬编码订单微服务则后续的维护会变得异常复杂。
所以,在微服务开发的过程中,需要引入服务治理功能,实现微服务之间的动态注册与发现,从此刻开始我们正式进入SpringCloud实战

1.2 什么是consul?

Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。
提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows

1.3 consul能干什么

1.3.1 服务发现

提供HTTP和DNS两种发现方式

1.3.2 健康监测

支持多种方式,HTTP、TCP、Docker、壳牌脚本定制化监控

1.3.3 KV存储

Key、Value的存储方式

1.3.4 多数据中心

Consul支持多数据中心

1.3.5 可视化Web界面

2. consul下载、查看版本和启动

1.3.1 consul下载

https://developer.hashicorp.com/consul/downloads

1.3.2 consul查看版本

1.点开文件夹,点击consul.exe启动或者cmd命令
2.consul --version 查看版本

在这里插入图片描述

1.3.3 consul启动

consul agent -dev
在这里插入图片描述
访问:http://localhost:8500/。访问到页面证明启动成功。
在这里插入图片描述

3. 服务入住consul中心

3.1 服务提供者 8001

3.1.1 引入pom依赖

 <!--SpringCloud consul discovery -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

3.1.2 yml中的配置:

server:
  port: 8001

# ==========applicationName + druid-mysql8 driver===================
spring:
  application:
    name: cloud-payment-service

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

# ========================mybatis===================
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.cloud.entities
  configuration:
    map-underscore-to-camel-case: true

3.1.2 主启动类上加入@EnableDiscoveryClient:

package com.atguigu.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;


@SpringBootApplication
@MapperScan("com.atguigu.cloud.mapper") //importtk.mybatis.spring.annotation.MapperScan;
@EnableDiscoveryClient//入住进服务
public class Main8001
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main8001.class,args);
    }
}

3.1.3 启动,成功入住

在这里插入图片描述

3.2 服务消费者80

3.2.1 引入pom:

<!--SpringCloud consul discovery -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

3.2.2 yml的配置:

server:
  port: 80

spring:
  application:
    name: cloud-consumer-order
  ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}

3.2.3 主启动类上加入:

package com.atguigu.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul为注册中心时注册服务
public class Main80
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main80.class,args);
    }
}

3.2.4 OrderController层:

package com.atguigu.cloud.controller;

import com.atguigu.cloud.entities.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class OrderController
{
   // public static final String PaymentSrc_URL="http://localhost:8001";//现在先硬编码写死。
    public static final String PaymentSrc_URL="http://cloud-payment-service";//服务注册中心的微服务名称
    @Resource
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer/pay/add")
    public ResultData addOrder(PayDTO payDTO)
    {
        /**
         * postForObject(url,request,responseType.class)
         * url表示的是地址值
         * request表示的是请求参数
         * responseType.class表示的是响应的类型
         */
        return restTemplate.postForObject(PaymentSrc_URL + "/pay/add", payDTO, ResultData.class);
    }

    @GetMapping(value = "/consumer/pay/get/{id}")
    public ResultData getPayInfo(@PathVariable("id") Integer id)
    {
        /**
         * getForObject(url,responseType.class,urlVariables,responseType.class)
         * url表示的是地址值
         * responseType.class表示的是响应的类型
         * urlVariables表示的是url中的参数值
         */
        return restTemplate.getForObject(PaymentSrc_URL + "/pay/get/"+id, ResultData.class,id);
    }

    //删除和修改,作业  全部查询

    /**
     * 删除
     * @param id
     * @return
     */
  /*  @GetMapping(value = "/consumer/pay/del/{id}")
    public ResultData delPayInfo(@PathVariable("id") Integer id)
    {
        *//**
         * getForObject(url,responseType.class,urlVariables,responseType.class)
         * url表示的是地址值
         * responseType.class表示的是响应的类型
         * urlVariables表示的是url中的参数值
         *//*
        return restTemplate.getForObject(PaymentSrc_URL + "pay/del/"+id, ResultData.class,id);
    }*/

    @DeleteMapping(value = "/consumer/pay/del/{id}")
    public ResultData delPayOrder(@PathVariable("id") Integer id)
    {
        /**
         * getForObject(url,responseType.class,urlVariables,responseType.class)
         * url表示的是地址值
         * responseType.class表示的是响应的类型
         * urlVariables表示的是url中的参数值
         */
      restTemplate.delete(PaymentSrc_URL + "/pay/del/"+id);
      return ResultData.success("删除成功");
    }

  /*  @GetMapping(value = "/consumer/pay/update")
    public ResultData updataOrder(PatDTO patDTO)
    {
        *//**
         * postForObject(url,request,responseType.class)
         * url表示的是地址值
         * request表示的是请求参数
         * responseType.class表示的是响应的类型
         *//*
        return restTemplate.postForObject(PaymentSrc_URL + "/pay/update", patDTO, ResultData.class);
    }*/

    @PutMapping(value = "/consumer/pay/update")
    public ResultData updateOrder(@RequestBody PayDTO payDTO)
    {
        /**
         * postForObject(url,request,responseType.class)
         * url表示的是地址值
         * request表示的是请求参数
         * responseType.class表示的是响应的类型
         */

        restTemplate.put(PaymentSrc_URL + "/pay/update", payDTO);
        return ResultData.success(payDTO);
    }


    @GetMapping(value = "/consumer/pay/list")
    public ResultData getPayAll()
    {
        /**
         * getForObject(url,responseType.class,urlVariables,responseType.class)
         * url表示的是地址值
         * responseType.class表示的是响应的类型
         * urlVariables表示的是url中的参数值
         */
        return restTemplate.getForObject(PaymentSrc_URL + "/pay/list", ResultData.class);
    }

    // 声明一个DiscoveryClient类型的变量discoveryClient
 @Resource
    private DiscoveryClient discoveryClient;
    // 声明一个@GetMapping类型的方法,路径为"/consumer/discovery",返回值为String类型
    @GetMapping("/consumer/discovery")
    public String discovery()
    {
        // 调用discoveryClient的getServices()方法,获取所有注册的服务名
        List<String> services = discoveryClient.getServices();
        // 遍历services
        for (String element : services) {
            // 打印出services中的元素
            System.out.println(element);
        }

        // 打印一条分隔符
        System.out.println("===================================");

        // 调用discoveryClient的getInstances()方法,获取指定服务的实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
        // 遍历instances
        for (ServiceInstance element : instances) {
            // 打印出instances中的元素的属性
            System.out.println(element.getServiceId()+"\t"+element.getHost()+"\t"+element.getPort()+"\t"+element.getUri());
        }

        // 返回第一个实例的服务ID和服务端口
        return instances.get(0).getServiceId()+":"+instances.get(0).getPort();
    }

}

3.2.5 启动服务,成功入住:

在这里插入图片描述

3.2.6 配置类RestTemplateConfig注意问题!!

因为consul天生就自带负载均衡,所以我们要加入 @LoadBalanced

package com.atguigu.cloud.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;
@Configuration
@LoadBalancerClient(
        //下面的value值大小写一定要和consul里面的名字一样,必须一样
        value = "cloud-payment-service",configuration = RestTemplateConfig.class)
//这个注解的作用是:在启动类上添加@LoadBalancerClient注解,并指定负载均衡的配置类
//cloud-payment-service指定consul中哪个服务,configuration = RestTemplateConfig.class这个类是自定义的负载均衡配置类
/*
默认的轮询负载均衡
public class RestTemplateConfig
{
    @Bean
    @LoadBalanced//因为consul天生就自带负载均衡,所以我们要加入 @LoadBalanced

    public RestTemplate restTemplate()
    {
        */
/**
 * 1. 创建一个公用的RestTemplate对象
 *//*

        return new RestTemplate();
    }
}
*/

3.3 三个注册中心异同点(CAP)

3.3.1 cap是什么?

C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance(分区容错性)

3.3.2 经典AP:

在这里插入图片描述

3.3.3 经典CP:

在这里插入图片描述

4. consul 统一配置

4.1 为什么需要统一配置?

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。比如某些配置文件中的内容大部分都是相同的,只有个别的配置项不同。就拿数据库配置来说吧,如果每个微服务使用的技术栈都是相同的,则每个微服务中关于数据库的配置几乎都是相同的,有时候主机迁移了,我希望一次修改,处处生效。
当下我们每一个微服务自己带着一个application.yml,上百个配置文件的管理…/(ㄒoㄒ)/~~

4.2 demo讲解

4.2.1 引入pom:

< !--SpringCloud consul config-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

4.2.2 配置yml:

4.2.2.1 bootstrap.yml

(applicaiton.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更加高
Spring Cloud会创建一个“Bootstrap Context”,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment
Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。 Bootstrap contextApplication Context有着不同的约定,所以新增了一个bootstrap.yml文件,保证Bootstrap ContextApplication Context配置的分离。
application.yml文件改为bootstrap.yml,这是很关键的或者两者共存
因为bootstrap.yml是比application.yml先加载的。bootstrap.yml优先级高于application.yml)

spring:
  application:
    name: cloud-payment-service
    ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
      config:
        profile-separator: '-' # default value is ",",we update '-'
        format: YAML

# config/cloud-payment-service/data
#       /cloud-payment-service-dev/data
#       /cloud-payment-service-prod/data
4.2.2.2 application.yml
server:
  port: 8001

# ==========applicationName + druid-mysql8 driver===================
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  profiles:
    #active: dev # 多环境配置加载内容dev/prod,不写就是默认default配置,这个对应的就是bootstrap.yml中的 config/cloud-payment-service-dev/data
    #active: prod
    active:
# ========================mybatis===================
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.cloud.entities
  configuration:
    map-underscore-to-camel-case: true

4.2.3 consul服务器key/value配置填写

4.2.3.1 参考规则

在这里插入图片描述
创建config文件夹,以/结尾
在这里插入图片描述
config文件夹下分别创建其它3个文件夹,以/结尾:
cloud-payment-service
cloud-payment-service-dev
cloud-payment-service-prod
在这里插入图片描述
上述3个文件夹下分别创建data内容,data不再是文件夹
在这里插入图片描述

4.2.3.2 测试controller类:
@Value("${server.port}")
private String port;

@GetMapping(value = "/pay/get/info")
private String getInfoByConsul(@Value("${atguigu.info}") String atguiguInfo)
{
    return "atguiguInfo: "+atguiguInfo+"\t"+"port: "+port;
}
4.2.3.3 测试服务:

通过修改application.yml里面的激活配置部分,进行内容的验证
测试地址:http://localhost:8001/pay/get/info
在这里插入图片描述

4.2.3.4 加上@RefreshScope // 动态刷新 :(当我们修改consul中的配置文件,后端也能得到对应的数据)
package com.atguigu.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * @auther zzyy
 * @create 2023-11-03 17:54
 */
@SpringBootApplication
@MapperScan("com.atguigu.cloud.mapper") //import tk.mybatis.spring.annotation.MapperScan;
@EnableDiscoveryClient //服务注册和发现
@RefreshScope // 动态刷新
public class Main8001
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main8001.class,args);
    }
}

5.总结

consul可以用来服务的注入管理,也可以用来统一入住进consul的服务的配置文件。(粗浅的总结和学习,还需更深层次的学习。)

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

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

相关文章

2024建博会|博联AI大模型全屋智能引领智能体验新纪元

7月8日&#xff0c;2024中国建博会&#xff08;广州&#xff09;在广交会展馆及保利世贸博览馆盛大启幕。BroadLink博联智能携AI大模型全屋智能以及AI商业照明解决方案惊喜亮相&#xff0c;全方位展示AI大模型在智能家居领域的前沿应用成果。 本次建博会&#xff0c;博联智能带…

3款ui设计师必备的高效软件,一定要收藏!

UI设计小伙伴们&#xff0c;你们是否在寻找那些能够让设计工作事半功倍的插件呢&#xff1f;今天&#xff0c;我要为大家带来3款UI设计软件中的高效软件&#xff0c;它们不仅能够极大提升我们的工作效率&#xff0c;还能让我们的设计更加专业和精致。让我们一起来看看这些不容错…

HTML CSS 基础复习笔记 - 框架、装饰、弹性盒子

自己复习前端基础&#xff0c;仅用于记忆&#xff0c;初学者不太适合 示例代码 - HTML <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initi…

数据结构 —— Dijkstra算法

数据结构 —— Dijkstra算法 Dijkstra算法划分集合模拟过程打印路径 在上次的博客中&#xff0c;我们解决了使用最小的边让各个顶点连通&#xff08;最小生成树&#xff09; 这次我们要解决的问题是现在有一个图&#xff0c;我们要找到一条路&#xff0c;使得从一个顶点到另一个…

前端JS特效第26波:jQuery日期时间选择器插件

jQuery日期时间选择器插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html> <html> <head lang"zh-CN"> <meta charset"UTF-8"> <title>jQuery日期时间选择器插件 - PHP中文网</t…

UI自动化测试是什么?什么项目适合做UI自动化测试

1. 页面对象设计模式的优势 (1) 创建可以跨多个测试用例共享的代码 (2) 减少代码的重复性 (3) 如果界面需要维护&#xff0c;只需要修改一个地方&#xff0c;修改以及维护的成本减少 2. 每个目录结构表达的意思 (1) Base:基础层&#xff0c;是用来编写定位元素 (2) Commo…

PL/SQL安装+汉化教程

PL/SQL安装教程 一、安装&#xff1a; 登陆官网&#xff1a;PL/SQL Developer - Allround Automations下载 下载PL/SQL稳定版本12.0.7 根据自己计算机版本安装相适配的版本。我这里安装X64-bit版本 进行安装&#xff1a; 根据情况去更改安装&#xff0c;我这里全部下一步…

【从零到一,如何搭建本地AI大模型】

摘要: 本文主要记录这一段时间对本地大模型搭建的心得。 作为一个资深程序员,在AI席卷全球的时候,深深感觉到了一丝危机感,不禁有一个想法不断在脑海闪现:我会不会真的哪一天被AI给取代了? 从哪入手 程序员出生的我,掌握了很多语言,从前端到数据库,再到运维,基本都…

Java基础-组件及事件处理(上)

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Swing 概述 MVC 架构 Swing 特点 控件 SWING UI 元素 JFrame SWING 容器 说明 常用方法 示例&a…

为什么选择虚拟艺术设计展览?艺术家应知的五个关键好处

随着技术的进步&#xff0c;虚拟艺术设计展览成为了展示艺术作品的重要途径。它不仅为艺术家们提供了新的展示平台&#xff0c;还打破了传统展览的局限。 1、扩大观众范围&#xff1a;打破地理限制 虚拟艺术设计展览能够打破地理限制&#xff0c;使得全球观众可以随时随地访问…

Androidstudio开发,天气预报APP

1.项目功能思维导图 2. 项目涉及到的技术点 数据来源&#xff1a;和风天气API使用okhttp网络请求框架获取api数据使用gson库解析json数据使用RecyclerViewadapter实现未来7天列表展示和天气指数使用PopupMenu 实现弹出选项框使用动画定时器实现欢迎页倒计时和logo动画使用Text…

《梦醒蝶飞:释放Excel函数与公式的力量》10.2 COMPLEX函数

第二节 10.2 COMPLEX函数 10.2.1函数简介 COMPLEX函数是Excel中的一个工程函数&#xff0c;用于将实部和虚部组合成一个复数。复数广泛应用于工程、电气、物理等领域&#xff0c;COMPLEX函数提供了方便的复数表示和计算方法。 10.2.2语法&#xff1a; COMPLEX(real_num, i_…

SpringSecurity-SpirngBoot-方法级授权(SpringSecurity6.3新特性)(四)

SpringSecurity-SpirngBoot-方法级授权&#xff08;SpringSecurity6.3新特性&#xff09;&#xff08;四&#xff09; 本章使用SpringSecurity6.3新特性实现数据级别的鉴权&#xff0c;主要的目的是实现不同权限的用户查询同一个方法&#xff0c;限制一些内容只能拥有特定权限…

自定义@AnonymousAccess注解

一.目的&#xff1a; 自定义AnonymousAccess注解&#xff0c;可以直接在controller上添加该注解使请求绕过权限验证进行匿名访问&#xff0c;便于快速调用调试以及部分不需要进行安全验证的接口。而不是每次都需要去SecurityConfig文件中进行修改。 二.流程&#xff1a; 三.实…

阿里MotionShop——AI视频工具:一键替换视频人物为3D虚拟角色~

近期AI相关的新奇应用层出不穷&#xff0c;今天小元老师要给大家安利一个由阿里巴巴研发的AI视频生成技术——MotionShop&#xff01; 1、一键替换3D虚拟角色 MotionShop通过视频处理、角色检测、背景修复等多重步骤&#xff0c;能够将视频中的人物角色&#xff0c;一键转换成…

Pytorch(笔记7损失函数类型)

前言 损失函数&#xff08;Loss Function&#xff09;&#xff1a;是定义在单个样本上的&#xff0c;是指一个样本的误差&#xff0c;度量模型一次预测的好坏。 代价函数&#xff08;Cost Function&#xff09;成本函数经验风险&#xff1a;是定义在整个训练集上的&#xff0c…

文件防止拷贝如何实现?这些攻略给你了

在信息爆炸的时代&#xff0c;数据安全成为企业和个人不可忽视的重要环节。文件的非法拷贝不仅可能侵犯知识产权&#xff0c;还可能导致敏感信息的泄露&#xff0c;进而引发严重的后果。 因此&#xff0c;了解并掌握文件防止拷贝的方法和技术至关重要。本文将详细介绍几种常见…

压测jmeter 插件 之 tps和响应时间图

1. 背景 进行压测ing 2. 需要插件 TPS 和 响应时间 3. 插件 在 选项-最下面-plugins Manager 在 Available Plugins 中 搜索 &#xff1a;jpgc - Standard Set 重启安装就好啦

12--RabbitMQ消息队列

前言&#xff1a;前面一章内容太多&#xff0c;写了kafka&#xff0c;这里就写一下同类产品rabbitmq&#xff0c;rabbitmq内容较少&#xff0c;正好用来过度一下&#xff0c;概念还是会用一些例子来说明&#xff0c;实际部署的内容会放在概念之后。 1、基础概念 1.1、MQ消息队…

年化15.73%:创业板指数布林带突破Backtrader策略(代码+数据)

原创文章第582篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 昨天咱们使用backtrader&#xff0c;重写了创业板动量趋势择时&#xff1a;年化19.2%&#xff1a;backtraderquantstats实现创业板动量择时(代码数据) 今天咱们换一个通道指标&#…