zoukankan      html  css  js  c++  java
  • 3--SpringCloud 和 Zookeeper周阳老师

    2021:3--SpringCloud 和 Zookeeper

    https://www.cnblogs.com/coderD/p/14350076.html SpringCloud

    https://www.cnblogs.com/coderD/p/14350073.html SpringCloud 和 Eureka

    https://www.cnblogs.com/coderD/p/14350082.html SpringCloud 和 Zookeeper

    https://www.cnblogs.com/coderD/p/14350086.html SpringCloud-Ribbon/OpenFeign

    https://www.cnblogs.com/coderD/p/14350091.html SpringCloud:Hystrix 断路器

    https://www.cnblogs.com/coderD/p/14350097.html SpringCloud:服务网关 gateway

    https://www.cnblogs.com/coderD/p/14350099.html SpringCloud:Config/Bus

    https://www.cnblogs.com/coderD/p/14350103.html SpringCloud:Stream/Sleuth

    https://www.cnblogs.com/coderD/p/14350110.html SpringCloud Alibaba:Nacos

    https://www.cnblogs.com/coderD/p/14350114.html SpringCloud Alibaba:Sentinel

    https://www.cnblogs.com/coderD/p/14350119.html SpringCloud Alibaba:Seata

    代码:https://gitee.com/xue--dong/spring-cloud

    阳哥脑图:https://gitee.com/xue--dong/spring-cloud

    主要内容

    1.  服务注册中:Zookeeper代替Eureka
    
    2.   Consul服务注册与发现
    复制代码
    

    1. 注册中心 Zookeeper

    zookeeper是一个分布式协调工具,可以实现注册中心功能
    
    关闭linux服务器防火墙后,启动zookeeper服务器
    systemctl stop firewalld
    
    zookeeper服务器取代Eureka服务器,zk作为服务注册中心
    复制代码
    

    2. 服务提供者

    2.1 新建 cloud-provider-payment8004

    1.  新建cloud-provider-payment8004
    复制代码
    

    2.2 pom

    2.  pom
    复制代码
    <dependencies>
    
            <!--SpringBoot整合zookeeper客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            </dependency>
            <!--引入我们自定义的公共api jar包-->
            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!--web/actuator这两个一般一起使用,写在一起-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--监控-->
            <dependency>
                <groupId>
                    org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!--Mybatis和SpringBoot的整合-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
            </dependency>
    
            <!--mysql-connector-java-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <!--热部署-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    复制代码
    

    2.3 yml

    3.  yml
    复制代码
         server:
          port: 8004
        
        spring:
          application:
            name: cloud-provider-payment
          cloud:
            zookeeper:
              connect-string: 192.168.92.130:2181
        
          datasource:
            type: com.alibaba.druid.pool.DruidDataSource      # 数据源
            driver-class-name: com.mysql.cj.jdbc.Driver     # mysql驱动包
            url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
            username: root
            password: root
    复制代码
    

    2.4 主启动类

    4.  主启动类
    复制代码
        @SpringBootApplication
        @EnableDiscoveryClient //开启服务发现
        public class PaymentMain8004 {
            public static void main(String[] args) {
                SpringApplication.run(PaymentMain8004.class, args);
            }
        }
    复制代码
    

    2.5 controller

    5.  controller
    复制代码
        @RestController
        public class PaymentController {
        
            @Value("${server.port}")
            private String serverPort;
        
            @RequestMapping(value="/payment/zk")
            public String paymentzk(){
                return "springcloud with zookeeper: "+serverPort+"	"+ UUID.randomUUID().toString();
            }
        }
    
    复制代码
    

    2.6 测试:解决 jar 包冲突

    6.  启动测试
    
        这里视频会出现一个jar冲突的异常
    复制代码
    

    img

        分析思路:
            
            找到代码中出错的地方,向启动入口处的报错,肯定是环境引起的。
            
            注意到提示zookeeper-3.5.6-beta。
            
            再想到我们自己安装的zookeeper版本,那就可能是jar包的冲突了。
            
            很可能是某个整合包自带的zookeeper包和我们服务器上的zookeeper版本不一样。
            
            发现我们导入的spring-zookeeper的整合包,包含了zookeeper-3.5.6-beta,我们要将其排除掉
    复制代码
    

    img

        怎么做:
        
            一般不会卸载zookeeper,因为其他系统可能正在使用这个zookeeper。
            
            所以我们排除掉包含的这个冲突的zookeeper包,引入一个服务器对应的jar包
            
    7.  我这里没报错。
    
        不知道是不是我的版本(3.6.1)比较高的原因
        
        我试着将整合包中的3.5.3版本的zookeeper剔除掉,引入3.6.1
    复制代码
            <!--SpringBoot整合zookeeper客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
                <!--排除掉自带的zookeepr3.5.3-->
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.zookeeper</groupId>
                        <artifactId>zookeeper</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!--引入对应服务器版本的zookeeper-->
            <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.6.1</version>
            </dependency>
    复制代码
    8.  启动:报错
        
        添加了3.6.1的zookeeper后,会报错:
    复制代码
    

    img

        那么很显然了,根据上面的分析,出错误在主启动类,关键词slf4j,logback。
        
        查看引入的3.6.1的zookeeper包:
    复制代码
    

    img

        我导入的slf4j:
    复制代码
    

    img

        我选择排除掉其中的3.6.1的zookeeper包其中的三个日志相关的jar包,用自己的。
    复制代码
    

    img

        成功排除掉。
        
        注意:groupId和artifactId的对应。
     
        重启服务:启动成功!!!
    
    9.  查看一下服务是否注册成功
    
        1.  进入zookeeper容器中
        
            docker exec -it 66805aa71339 /bin/bash
            
        2.  客户端连接
        
            ./bin/zkCli.sh
    复制代码
    

    img

        3.  查看服务
        
            ls /
            ls /services
    复制代码
    

    img

            注册成功!!!
            
            继续进去看:
            
            ls /services/cloud-provider-payment
            
            ls /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045
    复制代码
    

    img

        4.  几个概念
        
            1.  /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045
            
            这整个东西就是zookeeper的zNode节点。
            
            
            2.  我们通过get命令,获取zookeeper中的节点信息
    复制代码
    

    img

                这一大串,就是我们服务存在zookeeper的基本信息--JSON串。
                
            3.  我们在线解析一下这个json串
    复制代码
    

    img

    2.7 思考

    10. 思考
    
            注册到zookeeper的微服务是一个zNode节点,这个服务节点时临时节点还是持久节点?
            
            我们注册进zookeeper的服务,会自动生成一个流水号id
    复制代码
    

    img

            1.  关闭掉8004服务
            
            2.  查看zookeeper中是否还有该微服务。
    复制代码
    

    img

                发现刚断开连接时zookeeper还保存着该服务,等待一段时间剔除了断开连接的微服务。
                
            3.  所以注册到zookeeper的微服务节点是临时节点。
            
            
            4.  再重新启动8004的微服务
    复制代码
    

    img

                服务又注册了进来,但是流水id换了。
                
            5.  zookeeper比eureka更加心狠干脆。
    复制代码
    

    3. 服务消费者

    3.1 新建 cloud-consumerzk-order80

        1.  新建cloud-consumerzk-order80
    复制代码
    

    3.2 pom

            <dependencies>
        
                <!--SpringBoot整合zookeeper客户端-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
                    <!--排除掉自带的zookeepr3.5.3-->
                    <exclusions>
                        <exclusion>
                            <groupId>org.apache.zookeeper</groupId>
                            <artifactId>zookeeper</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
                <!--引入对应服务器版本的zookeeper-->
                <dependency>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                    <version>3.6.1</version>
                    <exclusions>
                        <exclusion>
                            <groupId>org.slf4j</groupId>
                            <artifactId>slf4j-log4j12</artifactId>
                        </exclusion>
                        <exclusion>
                            <groupId>org.slf4j</groupId>
                            <artifactId>slf4j-api</artifactId>
                        </exclusion>
                        <exclusion>
                            <groupId>log4j</groupId>
                            <artifactId>log4j</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
        
        
                <!--引入我们自定义的公共api jar包-->
                <dependency>
                    <groupId>com.atguigu.springcloud</groupId>
                    <artifactId>cloud-api-commons</artifactId>
                    <version>${project.version}</version>
                </dependency>
        
                <!--web/actuator这两个一般一起使用,写在一起-->
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <!--监控-->
                <dependency>
                    <groupId>
                        org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-actuator</artifactId>
                </dependency>
        
                <!--Mybatis和SpringBoot的整合-->
                <dependency>
                    <groupId>org.mybatis.spring.boot</groupId>
                    <artifactId>mybatis-spring-boot-starter</artifactId>
                </dependency>
        
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                    <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
                </dependency>
        
                <!--mysql-connector-java-->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                </dependency>
                <!--jdbc-->
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-jdbc</artifactId>
                </dependency>
                <!--热部署-->
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-devtools</artifactId>
                    <scope>runtime</scope>
                    <optional>true</optional>
                </dependency>
        
                <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <optional>true</optional>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <scope>test</scope>
                </dependency>
        
            </dependencies>
    复制代码
    

    3.3 yml

        server:
          port: 80
        
        spring:
          application:
            name: cloud-consumerzk-order
          cloud:
            zookeeper:
              connect-string: 192.168.92.130:218
    复制代码
    

    3.4. 主启动类

        @SpringBootApplication
        @EnableDiscoveryClient
        public class OrderZKMain80 {
            public static void main(String[] args) {
                SpringApplication.run(OrderZKMain80.class, args);
        
            }
        }
    复制代码
    

    3.5. 业务类

        package com.atguigu.springcloud.config;
        
        @Configuration
        public class ApplicationContextConfig {
        
            @Bean
            @LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
            public RestTemplate getRestTemplate(){
                return new RestTemplate();
            }
        }
      
        package com.atguigu.springcloud.controller; 
        
        @RestController
        @Slf4j
        public class OrderZKController {
        
            //由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
            public static final  String INVOKE_URL = "http://cloud-provider-payment";
        
            @Resource
            private RestTemplate restTemplate;
        
            //返回String测试一下:不交互数据库了
            @GetMapping("/consumer/payment/zk")
            public String paymentInfo(){
                String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk", String.class);
        
                return result;
            }
        }
    复制代码
    

    3.6. 测试

        1.  服务注册进zookeeper成功
    复制代码
    

    img

        2.  服务调用成功
    复制代码
    

    img

    4 Consul 服务注册与发现

    4.1 Consul 简介

    1.  是什么:微服务的服务注册中心
    复制代码
    

    官网

        Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司采用Go语言开发
        
        提供了微服务系统中心的服务治理,配置中心,控制总线等功能。这些功能中的每一个都可以根据需要
        单独使用,也可以一起使用,以构建全方位的服务网格。
        
        总之Consul提供了一种完整的服务网格解决方案。
        
        它具有很多优点:
            包括,基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议支持跨数据中心的WAN集群。
            
            提供图形界面 跨平台,支持Linux,MAC,Windows
    
    2.  能干嘛:The key features of Consul are:
    
            Service Discovery:服务发现,提供HTTP和DNS两种发现方式
            
            Health Checking: 健康检查,支持多种方式,HTTP,TCP,Docker,Shell脚本定制化
            
            KV Store:   Key,Value的存储方式
            
            Secure Service Communication: 安全的服务交流
            
            Multi Datacenter:多数据中心
            
            可视化web界面
            
            
    3.  下载
    复制代码
    

    下载

    4.  怎么用
    复制代码
    

    中文文档

    4.2 安装并运行 Consul

        1.  下载完成后只有一个consul.exe文件
            
            硬盘路径下双击运行
        
        2.  cmd:
            查看版本:   D:Developer_ToolsConsul>consul --version
            
            使用开发者模式启动:  D:Developer_ToolsConsul>consul agent -dev
            
        3.  可视化web页面:localhost:8500
    复制代码
    

    img

    5. 生产者服务注册:consul

    5.1 新建 Module 支付服务:cloud-providerconsul-payment8006

    5.2 pom

    <dependencies>
            <!--consul和SpringCloud的整合-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            </dependency>
    
            <!--引入我们自定义的公共api jar包-->
            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!--web/actuator这两个一般一起使用,写在一起-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--监控-->
            <dependency>
                <groupId>
                    org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!--Mybatis和SpringBoot的整合-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
            </dependency>
    
            <!--mysql-connector-java-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <!--热部署-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    复制代码
    

    5.3 yml

        # 微服务端口号
        server:
          port: 8006
        
        # 微服务名称
        spring:
          application:
            name: cloud-provider-payment
        
          datasource:
            type: com.alibaba.druid.pool.DruidDataSource      # 数据源
            driver-class-name: com.mysql.cj.jdbc.Driver     # mysql驱动包
            url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
            username: root
            password: root
          cloud:
            consul:
              host: localhost
              port: 8500
              discovery:
                service-name: ${spring.application.name}
        
        
        
        mybatis:
          mapper-locations: classpath:mapper/*.xml                # 扫描类路径下mapper文件夹下的.xml配置文件
          type-aliases-package: com.atguigu.springcloud.entities  # 该包所有Entity类,取默认别名
    复制代码
    

    5.4 主启动类

        @SpringBootApplication
        @EnableDiscoveryClient
        public class PaymentMain8006 {
            public static void main(String[] args) {
                SpringApplication.run(PaymentMain8006.class, args);
            }
        }
    复制代码
    

    5.5 controller

        @RestController
        @Slf4j
        public class PaymentController {
        
            @Value("${server.port}")
            private String serverPort;
        
            @RequestMapping(value="/payment/consul")
            public String paymentConsul(){
                return "springcloud with consul: "+serverPort+"	"+ UUID.randomUUID().toString();
            }
        }
    复制代码
    

    5.6 测试

        启动8006服务
    复制代码
    

    img

        注册成功
    复制代码
    

    img

    6. 消费者服务注册:consul

    6.1 新建 module

    新建module cloud-consumerconsul-order80
    复制代码
    

    6.2 pom

    <dependencies>
    
            <!--consul和SpringCloud的整合-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            </dependency>
    
            <!--引入我们自定义的公共api jar包-->
            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!--web/actuator这两个一般一起使用,写在一起-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--监控-->
            <dependency>
                <groupId>
                    org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!--热部署-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    复制代码
    

    6.3 yml

        server:
          port: 80
        
        spring:
          application:
            name: cloud-consumer-order
        
          cloud:
            consul:
              host: localhost
              port: 8500
              discovery:
                service-name: ${spring.application.name}
    复制代码
    

    6.4 主启动类

        @SpringBootApplication
        @EnableDiscoveryClient
        public class OrderConsulMain80 {
        
            public static void main(String[] args) {
                SpringApplication.run(OrderConsulMain80.class, args);
            }
        }
    复制代码
    

    6.5 controller 和 config

    config
    复制代码
        @Configuration
        public class ApplicationContextConfig {
        
            @Bean
            @LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
            public RestTemplate getRestTemplate(){
                return new RestTemplate();
            }
        }
    复制代码
    controller
    复制代码
        @RestController
        @Slf4j
        public class OrderConsulController {
        
            //由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
            public static final  String INVOKE_URL = "http://consul-provider-payment";
        
            @Resource
            private RestTemplate restTemplate;
        
            //返回String测试一下:不交互数据库了
            @GetMapping("/consumer/payment/consul")
            public String paymentInfo(){
                String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
        
                return result;
            }
        }
    复制代码
    

    6.6 启动测试

    img

    7. 三个注册中心的异同点

    img

        CAP:理论
        
            Eureka主要保证高可用:AP
            
            Zookeeper/Consul主要保证数据的一致:CP
            
            
        web界面:
            Eureka/Consul都有一个web界面。
            Zookeeper只有一个linux客户端。
    复制代码
    

    7.1

        从CAP理论分析一下异同:
        
            Eureka主要满足AP
            
            Zookeeper/Consul主要满足CP
            
            C:Consistency 强一致性
            A:Avaliability 可用性
            P: Partition tolerance 分区容错性
            
                P在分布式中永远都要保证。
                所以要么是CP,要么是AP。
                三个只能占2个。
            
            CAP理论关注粒度是数据,而不是整体系统设计的角度。
            
        
        1.  最多只能同时较好的满足两个
        
            CAP理论的核心:一个分布式系统不可能同时很好的满足三个需求。因此根据CAP原理将
            NOSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类。
            
            CA:单点集群,满足一致性,可用性的系统,通常扩展性不强大。
            
            CP:满足一致性,分区容错性的系统,对数据一致性要求高,所以性能负担大。
                Zookeeper/Consul
                
                要求数据必须一致性。
            
            AP:满足可用性,分许容错性的系统,通常可能对一致性要求低一些。
                Eureka
                
                场景:商场,暂时不一致错一点没关系,只要能正常访问下单即可。
            
            Eureka通过设置一些属性,也可以通过牺牲高可用性实现一致性的要求。
                
        2.  分布式必须满足:P: Partition tolerance 分区容错性
    复制代码
    
  • 相关阅读:
    后端MVC与前端MVVM的区别
    解析身份证号
    awk的执行方式
    案例九:shell脚本自动创建多个新用户,并设置密码
    一键配置tomcat定期日志清理功能
    date命令
    将dict.define转化成dict.txt
    FastDFS 配置 Nginx 模块及访问测试
    nohup命令的用法
    手把手教你如何玩转消息中间件(ActiveMQ)
  • 原文地址:https://www.cnblogs.com/coderD/p/14350082.html
Copyright © 2011-2022 走看看