SpringCloud SpringCloud 笔记版本 编码构建微服务架构 IDEA 创建 Project 工作空间 微服务 Cloud 父工程整体聚合 Project New Project 聚合总父工程名称 Maven选版本 字符编码 注意生效激活 Java 编译版本 父工程 pom REST 微服务构建 微服务提供商支付 Module 模块 创建 cloud-provider-payment8001 模块 修改 pom 文件 application.yaml 主启动 业务类 建表SQL entity mapper service controller 热部署 Devtools 添加 Devtools 依赖 修改父工程 pom.xml 文件 修改 IDEA 设置 更新值 微服务消费者订单 Module 模块 创建 cloud-consumer-order81 模块 修改 pom.xml 文件 application.yaml 主启动 业务类 entity RestTemplate ApplicationContextConfig controller 工程重构 观察问题 新建公共工程 修改 pom.xml 文件 写公共部分 maven 打包 81和8001端口服务改造 目前工程样图 Eureka 注册和发现服务 概述 单机 Eureka 构建步骤 创建 EurekaServer 服务注册中心 创建 Module 修改 pom.xml 主启动 application.yaml 测试 注册8001端口服务 EurekaServer 成为服务提供商 provider 修改 pom.xml 修改 application.yaml 修改主启动类 测试 注册81端口服务 EurekaServer 为消费者服务consumer 修改 pom.xml 修改 application.yaml 修改主启动类 测试 集群 Eureka 构建步骤 EurekaServer建设集群环境的步骤 创建 Module 修改 pom.xml 主启动 修改映射配置 application.xml 7001 7002 测试 8001微服务发布 Eureka 集群中 application.yaml 发布81微服务 Eureka 集群中 application.yaml 测试 8001集群环境建设 创建 Module 修改 pom.xml application.xml 主启动 业务类 修改8001/8002的Controller 测试 问题 负载均衡 修改81服务 Controller 赋予 RestTemplate 负载平衡能力 actuator 完善微服务信息 修改服务名称 IP 信息提示 服务发现 Discovery 修改8001的 Controller 修改8001主启动类 日志打印 Eureka 自我保护 概述 故障现象 导致原因 关闭自我保护 修改7001的 application.yaml 效果 修改8001的 application.yaml 测试 Consul 注册和发现服务 Consul 简介 概述 Spring Cloud Consul 特性 下载地址 官方文档 安装并运行 Consul 服务提供者 新建 Module 支付服务 provider8006 POM YAML 主启动 Controller 测试 服务消费者 新建 Module 消费服务 order81 POM YAML 主启动 配置 Bean Controller 测试 Ribbon 调用负载均衡服务 概述 Ribbon 负载均衡演示 架构说明 POM 二说 RestTemplate 的使用 官网 getForObject方法/getForEntity方法 Ribbon 核心组件 IRule IRule 如何替换 配置细节 新建 package 新建 MySelfRule 规则类 添加主启动类 @RibbonClient 测试 Ribbon 负载均衡算法 原理 OpenFeign 调用服务接口 概述 OpenFeign 使用步骤 新建 cloud-consumer-feign-order81 POM YAML 主启动 业务类 业务逻辑接口 @FeignClient 配置调用 provider 服务 Controller 测试 总结 OpenFeign 超时控制 概述 超时设置 故意设置超时演示错误 服务提供商8001故意写暂停程序 服务消费者81添加超时方法PaymentFeignService 服务消费者81添加超时方法OrderFeignController 测试 YML 需要在文件中打开 OpenFeign 客户端超时控制 OpenFeign 日志打印功能 概述 日志级别 启用日志 配置日志 Bean YAML 打开文件中的日志 Feign 客户端 效果 Hystrix 断路器 分布式系统面临的问题 Hystrix 概述 Hystrix 重要概念 Hystrix 案例 新建 cloud-provider-hystrix-payment8001 POM YAML 主启动 业务类 service controller 测试 新建 cloud-consumer-feign-hystrix-order81 POM YAML 主启动 业务类 service controller 正常测试 Jmeter高并发测试 如何解决 服务降级 8001fallback 业务类启用 主启动激活 效果 80fallback 主启动 Controller 测试 统一服务降级 解耦合 YAML 创建 Service 实现类 Service 接口 Controller 测试 服务熔断 什么是熔断 实操 PaymentService PaymentController 测试 总结 熔断类型 断路器打开或关闭的条件 断路器在什么情况下开始工作? 断路器打开后 ALL 配置 服务限流 服务监控 HystrixDashboard 仪表盘9001 新建 cloud-consumer-hystrix-dashboard9001 POM YAML 主启动 所有 Provider 微服务提供类都需要监控依赖配置 启动9001 断路器演示(服务监控)hystrixDashboard) 修改cloud-provider-hystrix-payment8001 监控测试 9001监控8001 Gateway 新一代网关 概述 三个核心概念 入门配置 新建 cloud-gateway-gateway9527 POM YAML 主启动 没有业务类 YAML 新网关配置 测试 网关配置在代码中 负载均衡 Predicate 的使用 概述 常用的 Route Predicate After Route Predicate Before Route Predicate Between Route Predicate 时间格式 Cookie Route Predicate Header Route Predicate Host Route Predicate Method Route Predicate Path Route Predicate Query Route Predicate Filter 的使用 定制过滤器 SpringCloud Config 分布式配置中心 概述 Config 配置和测试服务端 创建 springcloud-config 仓库 搭建本地仓库 微服务搭建 新建 cloud-config-center-3344 POM YAML 主启动 测试 读取规则的配置 Config 配置和测试客户端 新建 cloud-config-client-3355 POM boostrap.yaml 概述 主启动 业务类 测试 Config 动态刷新客户端 POM 引入 actuator 监控 修改 YAML 暴露监控端口 Controller 上增加 @RefreshScope 注解 测试 SpringCloud Bus 消息总线 SpringCloud Stream 消息驱动 SpringCloud Alibaba SprngCloud Alibaba Nacos服务注册和配置中心 Nacos 简介 安装并运行 Nacos Nacos 作为服务注册中心演示 基于Nacos的服务提供者 新建 cloudalibaba-provider-payment9001 父 POM 本 POM YAML 业务类 测试 新建 cloudalibaba-provider-payment9002 基于 Nacos 的服务消费者 新建 cloudalibaba-consumer-nacos-order83 POM YAML 主启动 业务类 测试 Nacos 作为服务配置中心演示 Nacos 作为配置中心-基础配置 新建 cloudalibaba-config-nacos-client3377 POM YAML 主启动 业务类 在 Nacos 中添加配置信息 测试 Nacos 作为配置中心-分类配置 概述 DataID方案 Group方案 Namespace方案 Ncos 作为配置中心-通用配置 Nacos 集群和持久化配置 官网说明 Windows 持久化 derby 到 MySql 切换配置步骤 执行 SQL 脚本 修改配置文件 Linux 版 Nacos + MySQL 生产环境配置 安装 Nacos 切换数据库 Nacos 集群配置 Nginx 配置 测试 SpringCloud Alibaba Sentinel实现熔断与限流 概述 安装 Sentinel 控制台 初始化演示工程 创建 Sentinel 微服务 新建 Module POM YAML 主启动 业务类 启动微服务8401 查看 Sentinel 监控页 Sentinel 懒加载 流控规则 基本介绍 流控模式 直接 QPS 的流量控制 线程数的流量控制 关联 操作 测试 流控效果 快速失败 预热 匀速排队 降级规则 官网 熔断策略 慢调用比例 异常比例 异常数 热点 key 限流 Controller 配置 测试 结论 自定义错误方法 测试 RunTimeException 参数例外项 系统规则 概述 配置 @SentinelResource 官网概述 按资源名称限流+后续处理 RateLimitController 配置 测试 按照Url地址限流+后续处理 RateLimitController 配置 测试 自定义兜底方法面临的问题 客户自定义限流处理逻辑 创建 CustomerBlockHandler 类用于自定义限流处理逻辑 RateLimitController Sentinel 控制台配置 测试 进一步说明 服务熔断功能 Ribbon 系列 服务提供者 9003/9004 创建 Module POM YAML 主启动 业务类 服务消费者 84 创建 Module POM YAML 主启动 ApplicationContextConfig 业务类 测试 只配置 fallback Controller 测试 只配置 blockHandler Controller 配置 测试 fallback 和 blockHandler 都配置 Controller Sentinel 配置 测试 Feign 系列 POM YAML 主启动 业务类 Service Service实现类 Controller 测试 规则持久化 POM YAML rule-type 详解 Nacos 配置 flow 模式 json 串属性详解 测试 SpringCloud Alibaba Seata处理分布式事务 Seata 概述 Seata 术语 Seata 处理过程 Seata-TC 事务协调者搭建 下载地址 修改 file.conf 文件 创建数据库 Nacos 创建命名空间 修改 registry.conf 文件 启动 Seata 使用 Nacos 作为 Seata 的配置中心 修改 config.txt 向 Nacos 推送配置 订单/库存/账户业务数据库准备 分布式事务业务说明 创建业务数据库 创建对应的业务表 创建日志回滚表 创建 Maven 父工程 创建公共模块 POM CommonResult 统一返回结果 Account 实体 Order 实体 Storage 实体 创建账户服务 POM YAML 主启动 AccountMapper 接口 AccountMapper 配置文件 AccountService 接口 AccountServiceImpl 实现类 AccountController 创建库存服务 POM YAML 主启动 StorageMapper 接口 StorageMapper 配置文件 StorageService 接口 StorageServiceImpl 实现类 StorageController 创建订单服务 POM YAML 主启动 DataSourceProxyConfig OrderMapper OrderMapper 配置文件 OpenFeign 远程调用接口 AccountServiceOpenFeign StorageServiceOpenFeign OrderService 接口 OrderServiceImpl 实现 OrderController 测试 Spring Cloud OSS 文件上传到阿里云 开通 OSS 服务 Hello World Maven 代码 整合 Spring Maven application.yaml 代码
笔记版本 name version Spring Cloud Hoxton.SR1 Spring Boot 2.2.2.RELEASE Spring Cloud Alibaba 2.1.0.RELEASE Java Jav8 Maven 3.5及以上 MySQL 5.7及以上 image-20210530212848344
通过查看 Spring 官网选择任意版本的 Spring Cloud 可以查看官方推荐与这个版本的 Spring Cloud 配套使用的 Spring Boot 版本
微服务架构编码构建 IDEA 创建 Project 工作空间 微服务 Cloud 整体聚合父工程 Project New Project image-20210531114816847
聚合总父工程名字 image-20210531114938601
Maven选版本 不要使用 IDEA 自带的 Maven,使用自己安装的 Maven。
image-20210531115014315
字符编码 image-20210531115409526
注解生效激活 image-20210531115726938
Java 编译版本 image-20210531115854931
父工程 pom
<?xml version="1.0" encoding="UTF-8"?>4.0.0
org.hong SpringCloud 1.0-SNAPSHOT
pom
org.springframework.boot spring-boot-dependencies 2.2.2.RELEASE pom import org.springframework.cloud spring-cloud-dependencies Hoxton.SR1 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import mysql mysql-connector-java ${mysql.version} com.alibaba druid ${druid.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.spring.boot.version} junit junit ${junit.version} log4j log4j ${log4j.version} org.projectlombok lombok ${lombok.version} true org.springframework.boot spring-boot-maven-plugin true true REST 微服务构建 微服务提供者支付 Module 模块 创建 cloud-provider-payment8001 模块 注意:这里使用 Maven 创建,而不是使用 Spring Initializr。使用 Spring Initializr 也行,我习惯用这个。image-20210531151533848
修改 pom 文件
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-provider-payment8001</artifactId>
<dependencies>
<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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</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>
<!-- lombok -->
<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>
application.yaml server: port: 8001
spring: application: name: cloud-payment-service datasource: type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 1234
mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: org.hong.springcloud.entity # 所有Entity别名类所在包 主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args); } } 业务类 建表SQL CREATE TABLE payment
( id
bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘ID’, serial
varchar(200) DEFAULT ‘’, PRIMARY KEY (id
) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 – 自己加几条数据 entity 主实体 Payment
package org.hong.springcloud.entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data @AllArgsConstructor @NoArgsConstructor public class Payment implements Serializable { private Long id; private String serial; } json 封装体 CommonResult
package org.hong.springcloud.entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class CommonResult { private Integer code; private String message; private T data;
public CommonResult(Integer code, String message){
this(code, message, null);
}
} mapper mapper 接口 PaymentMapper
package org.hong.springcloud.mapper;
import org.apache.ibatis.annotations.Mapper; import org.hong.springcloud.entity.Payment;
@Mapper public interface PaymentMapper { int save(Payment payment);
Payment getPaymentById(Long Id);
} mapper 映射文件 PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> INSERT INTO payment(serial) VALUES (#{serial}); SELECT id, serial FROM payment WHERE id = #{id} service 接口 PaymentServicepackage org.hong.springcloud.service;
import org.hong.springcloud.entity.Payment;
public interface PaymentService { int save(Payment payment);
Payment getPaymentById(Long id);
} 实现类
package org.hong.springcloud.service.serviceimpl;
import org.hong.springcloud.entity.Payment; import org.hong.springcloud.mapper.PaymentMapper; import org.hong.springcloud.service.PaymentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
@Service public class PaymentServiceImpl implements PaymentService { @Autowired private PaymentMapper paymentMapper;
@Override
public int save(Payment payment) {
return paymentMapper.save(payment);
}
@Override
public Payment getPaymentById(Long id) {
return paymentMapper.getPaymentById(id);
}
} controller package org.hong.springcloud.controller;
import lombok.extern.slf4j.Slf4j; import org.hong.springcloud.entity.CommonResult; import org.hong.springcloud.entity.Payment; import org.hong.springcloud.service.PaymentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
@RestController @RequestMapping("/payment") @Slf4j public class PaymentController { @Autowired private PaymentService paymentService;
@PostMapping
public CommonResult<Payment> save(@RequestBody Payment payment){
int result = paymentService.save(payment);
log.info("****插入结果:" + result);
if(result > 0){
return new CommonResult(200, "插入数据库成功", result);
}else{
return new CommonResult(444, "插入数据库失败", null);
}
}
@GetMapping("/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("****查询结果:" + payment);
if(payment != null){
return new CommonResult(200, "查询成功", payment);
}else{
return new CommonResult(444, "没有对应记录, 查询" + id, null);
}
}
} 测试运行,没问题
热部署 Devtools 不配也行
添加 Devtools 依赖 哪个微服务需要使用就添加到哪个微服务的 pom.xml 文件中
org.springframework.boot spring-boot-devtools runtime true 修改父工程的 pom.xml 文件 把下面这一段粘贴到聚合父类总工程的pom.xml里 org.springframework.boot spring-boot-maven-plugin true true 修改 IDEA 设置 image-20210531170533030更新值 使用快捷键 ctrl + shift + alt + / 打开如下对话框
image-20210531171340731
image-20210531171612298
微服务消费者订单 Module 模块 创建 cloud-consumer-order81 模块 步骤跟上面一样
修改 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-consumer-order81</artifactId>
<dependencies>
<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>
application.yaml # 端口被占用就使用别的端口 server: port: 81 主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class OrderMain81 { public static void main(String[] args) { SpringApplication.run(OrderMain81.class, args); } } 业务类 entity 81端口需要进行支付操作,支付操作在8001端口,而支付操作的业务在8001端口,因此81端口不应该出现与支付相关的 service、mapper
81端口需要去调用8001端口暴露的接口,因此81端口需要 controller
81端口的 controller 也需要接收值和返回值,因此81端口需要 entity
主实体 Payment
package org.hong.springcloud.entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data @AllArgsConstructor @NoArgsConstructor public class Payment implements Serializable { private Long id; private String serial; } json 封装体 CommonResult
package org.hong.springcloud.entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class CommonResult { private Integer code; private String message; private T data;
public CommonResult(Integer code, String message){
this(code, message, null);
}
} RestTemplate RestTemplate 提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问 restful 服务模板类,是 Spring 提供的用于访问 Rest服务的客户端模板工具集。简单的说,通过 RestTemplate 可以让81端口调用到8001端口暴露的接口。与 JdbcTemplate、RedisTemplate 一样,RestTemplate 也需要注入到 IOC 容器中。
ApplicationContextConfig package org.hong.springcloud.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class ApplicationContextConfig { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } } controller package org.hong.springcloud.controller;
import lombok.extern.slf4j.Slf4j; import org.hong.springcloud.entity.CommonResult; import org.hong.springcloud.entity.Payment; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate;
@RestController @RequestMapping("/consumer") @Slf4j public class OrderController { public static final String PAYMENT_URL = “http://localhost:8001/”;
@Autowired
private RestTemplate restTemplate;
@PostMapping("/payment")
public CommonResult<Payment> save(@RequestBody Payment payment){
return restTemplate.postForObject(PAYMENT_URL + "payment", payment, CommonResult.class);
}
@GetMapping("/payment/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL + "/payment/" + id, CommonResult.class);
}
} 工程重构 观察问题 两个微服务中都有一个公共的部分,造成了代码的冗余
image-20210531213734650
新建公共工程 新建 cloud-api-commons 工程,公共部分写这个工程里面。怎么创建就不演示了,跟上面一样。
修改 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-api-commons</artifactId>
<dependencies>
<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>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
编写公共部分 从任意一个微服务中,复制一份 entity 包下的内容到 cloud-api-commons 中。
maven 打包 先运行 clean,再运行 install,打包到本地仓库。
image-20210531215631198
改造81和8001端口服务 删除各自的原先有过的 entity 文件夹
在各自的 pom.xml 添加依赖
org.hong cloud-api-commons ${project.version} 将报错的地方导入正确的类路径目前工程样图 image-20210601102216200
Eureka 服务注册与发现 Eureka 已经停止更新了,进入了维护状态
概述 Eureka 包含两个组件:Eureka Server 和 Eureka Client
Eureka Server 提供服务注册服务 各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
Eureka Client 通过注册中心进行访问 是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
单机 Eureka 构建步骤 创建 EurekaServer 服务注册中心 创建 Module cloud-eureka-server7001
修改 pom.xml
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>org.hong</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot 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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication // @EnableEurekaServer: 表明当前服务是服务注册中心 @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } } application.yaml server: port: 7001
eureka: instance: hostname: localhost #eureka服务端的实例名称 client: #false表示不向注册中心注册自己。 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。 defaultZone: http:// e u r e k a . i n s t a n c e . h o s t n a m e : {eureka.instance.hostname}: eureka.instance.hostname:{server.port}/eureka/ 测试 浏览器访问 http://localhost:7001/
image-20210601114911166
No instances available 没有服务被发现,因为没有注册服务进来当然不可能有服务被发现
将8001端口服务注册进 EurekaServer 成为服务提供者 provider 修改 pom.xml
org.springframework.cloud spring-cloud-starter-netflix-eureka-client 修改 application.yaml 直接粘贴到 applicaiton.yaml 文件中,eureka 节点就是根节点eureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true #服务注册地址 service-url: defaultZone: http://localhost:7001/eureka 修改主启动类 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication // 只加了这一个注解, 表明当前服务是Client @EnableEurekaClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } } 测试 先要启动 EurekaServe,再启动 EurekaClient,访问 http://localhost:7001/
image-20210601120854556
如果出现了服务名称代表成功,这个服务名称就是我们在 yaml 中配置的 spring.appliction.name 的值。
spring: application: name: cloud-payment-service 将81端口服务注册进 EurekaServer 成为服务服务消费者consumer 修改 pom.xml
org.springframework.cloud spring-cloud-starter-netflix-eureka-client 修改 application.yaml spring: application: name: cloud-order-serviceeureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka 修改主启动类 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient public class OrderMain81 { public static void main(String[] args) { SpringApplication.run(OrderMain81.class, args); } } 测试 先启动 EurekaServer,7001服务;再要启动服务提供者provider,8001服务;访问 http://localhost:7001/
image-20210601122502892
浏览器访问 http://localhost:81/consumer/payment/1 进行测试
集群 Eureka 构建步骤 Eureka 系统架构,Eureka Server 使用集群方式 ( 如果使用单机,Eureka 服务器一旦宕机,所有的服务都无法调用 ),Service Provider ( 服务提供者 )也使用集群;Service Consumer ( 服务使用者 ) 就不管我们的事情了。
image-20210601203157910
EurekaServer集群环境构建步骤 创建 Module 新建 cloud-eureka-server7002
修改 pom.xml
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-eureka-server7002</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>org.hong</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot 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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication @EnableEurekaServer public class EurekaMain7002 { public static void main(String[] args) { SpringApplication.run(EurekaMain7002.class, args); } } 修改映射配置 打开 C:\Windows\System32\drivers\etc 文件夹下的 host 文件添加如下配置
直接添加到host文件的最后面
作用: 浏览器访问eureka7001.com相当于访问127.0.0.1, 同理eureka7002.com也是
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 添加完后打开 cmd 刷新 dns 缓存,ipconfig/flushdns
application.xml 7001 server: port: 7001
eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url: # 7001与7002相互守望, 相互注册, 如果有多个用逗号分割 defaultZone: http://eureka7002.com:7002/eureka/ 7002 server: port: 7002
eureka: instance: hostname: eureka7002.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7001.com:7001/eureka/ 测试 启动 7001 和 7002,并访问 http://eureka7001.com:7001/ 和 http://eureka7002.com:7002/
image-20210601174654616
image-20210601174725185
7001访问页面可以看到7002,反之7002可以看到7001,环境构建成功
8001微服务发布到 Eureka 集群中 application.yaml eureka: client: service-url: # 将8001微服务发布到到Eureka集群的每个节点中 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版 81微服务发布到 Eureka 集群中 application.yaml eureka: client: service-url: # 将81微服务发布到到Eureka集群的每个节点中 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版 测试 先要启动 EurekaServer,7001/7002服务;
再要启动服务提供者 provider,8001
再要启动消费者,81
访问 http://eureka7001.com:7001/、http://eureka7002.com:7002/,观察注册进去的服务
image-20210601202841098
出现上述的2个服务代表搭建成功
支付服务提供者8001集群环境构建 创建 Module 新建 cloud-provider-payment8002
修改 pom.xml
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-provider-payment8002</artifactId>
<dependencies>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</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>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>org.hong</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
application.xml server: port: 8002 spring: application: # 服务名称不用改, 与8001一致 name: cloud-payment-service datasource: type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 1234
eureka: client: #表示是否将自己注册进EurekaServer默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: #defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: org.hong.springcloud.entity # 所有Entity别名类所在包 主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient public class PaymentMain8002 { public static void main(String[] args) { SpringApplication.run(PaymentMain8002.class, args); } } 业务类 直接从8001微服务中粘贴过来
修改8001/8002的Controller 修改的目的:查看当前调用的是哪个端口的服务
package org.hong.springcloud.controller;
import lombok.extern.slf4j.Slf4j; import org.hong.springcloud.entity.CommonResult; import org.hong.springcloud.entity.Payment; import org.hong.springcloud.service.PaymentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*;
@RestController @RequestMapping("/payment") @Slf4j public class PaymentController { @Autowired private PaymentService paymentService;
// 当前服务的端口号
@Value("${server.port}")
private String serverPort;
@PostMapping
public CommonResult<Payment> save(@RequestBody Payment payment){
int result = paymentService.save(payment);
log.info("****插入结果:" + result);
if(result > 0){
return new CommonResult(200, "插入数据库成功, serverPort: " + this.serverPort, result);
}else{
return new CommonResult(444, "插入数据库失败", null);
}
}
@GetMapping("/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("****查询结果:" + payment);
if(payment != null){
return new CommonResult(200, "查询成功, serverPort: " + this.serverPort, payment);
}else{
return new CommonResult(444, "没有对应记录, 查询" + id, null);
}
}
} 测试 先要启动 EurekaServer,7001/7002服务;
再要启动服务提供者 provider,8001
再要启动消费者,81
访问 http://eureka7001.com:7001/、http://eureka7002.com:7002/,观察注册进去的服务
image-20210601214232401
可以看到 cloud-payment-service 服务一共有2个,此时我们的支付服务提供者集群环境搭建成功
问题 访问 http://localhost:81/consumer/payment/1,观察返回的 json 数据。
{“code”:200,“message”:“查询成功, serverPort: 8001”,“data”:{“id”:1,“serial”:“hong”}} 无论我们发送多少次,真正执行查询的端口总是为8001端口。因为我们在进行服务调用的代码是写死的。
负载均衡 订单服务访问地址不能写死,应该使用微服务名称来进行访问。
修改81服务 Controller // 通过在eureka上注册过的微服务名称调用 public static final String PAYMENT_URL = “http://CLOUD-PAYMENT-SERVICE”; 我们再次访问 http://localhost:81/consumer/payment/1
image-20210601215439100
直接就 GG 了,因为我们少开启了一个功能。
赋予 RestTemplate 负载均衡的能力 在配置 RestTemplate 的方法上加上 @LoadBalanced 注解即可。这是 Ribbon 里面的东西。
package org.hong.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力 public RestTemplate getRestTemplate(){ return new RestTemplate(); } } 再次访问 http://localhost:81/consumer/payment/1,每次访问8001/8002都是交替出现
Ribbon 和 Eureka 整合后 Consumer 可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能了。
actuator 微服务信息完善 服务名称修改 修改 cloud-provider-payment8002 服务的 application.yaml
eureka: instance: # 自定义信息 instance-id: payment8001 效果
image-20210602103517161
IP 信息提示 修改 cloud-provider-payment8002 服务的 application.yaml
eureka: instance: # IP 信息显示 prefer-ip-address: true 效果
image-20210602104339897
服务发现 Discovery 对于注册进 Eureka 里面的微服务,可以通过服务发现来获得该服务的信息
修改8001的 Controller // import org.springframework.cloud.client.discovery.DiscoveryClient; 注意别导错包 // 容器里面已经有的, 我们获取就行 @Autowired private DiscoveryClient discoveryClient;
@GetMapping("/discovery") public Object discovery(){ // 获取注册到Eureka中的所有微服务名称 List services = discoveryClient.getServices(); services.forEach(element -> { log.info("****element:" + element); });
// 获得指定微服务名称下的所有实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
instances.forEach(instance -> {
log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
});
return discoveryClient;
} 修改8001的主启动类 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient // 添加@EnableDiscoveryClient注解 public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } } 日志打印 2021-06-02 11:21:15.078 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : ****element:cloud-payment-service 2021-06-02 11:21:15.079 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : ****element:cloud-order-service 2021-06-02 11:21:15.080 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : CLOUD-PAYMENT-SERVICE 192.168.200.1 8002 http://192.168.200.1:8002 2021-06-02 11:21:15.081 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : CLOUD-PAYMENT-SERVICE 192.168.200.1 8001 http://192.168.200.1:8001 image-20210602112318899
Eureka 自我保护 概述 保护模式主要用于一组客户端和 Eureka Server 之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server 将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
故障现象 如果在 Eureka Server 的首页看到以下这段提示,则说明Eureka进入了保护模式:
image-20210602112754416
导致原因 为了防止 Eureka Client 可以正常运行,但是 与 Eureka Server 网络不通情况下,Eureka Server 不会立刻将 Eureka Client 服务剔除
默认情况下,如果 EurekaServer 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server 将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与 Eureka Server 之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka 通过 “自我保护模式” 来解决这个问题——当 Eureka Server 节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。 它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让 Eureka 集群更加的健壮、稳定。
关闭自我保护 演示案例只启用7001和8001
修改7001的 application.yaml eureka: server: #关闭自我保护机制,保证不可用服务被及时踢除 enable-self-preservation: false #检测微服务存活的时间间隔, 单位为毫秒, 为了测试才改的, 不一定非要改 eviction-interval-timer-in-ms: 2000 效果 image-20210602120657459
修改8001的 application.yaml 为了测试才改的,缩小时间间隔
eureka: instance: #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒) lease-renewal-interval-in-seconds: 1 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务 lease-expiration-duration-in-seconds: 2 测试 先启动7001再启动8001
image-20210602121615323
再关闭8001
image-20210602121717159
Consul 服务注册与发现 Consul 简介 概述 Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。
提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows
Spring Cloud Consul 特性 服务发现:提供HTTP和DNS两种发现方式。
健康监测:支持多种方式,HTTP、TCP、Docker、Shell脚本定制化监控
KV存储:Key、Value的存储方式
多数据中心:Consul支持多数据中心
可视化Web界面
下载地址 https://www.consul.io/downloads
官方文档 https://www.springcloud.cc/spring-cloud-consul.html
安装并运行 Consul 官网安装说明:https://learn.hashicorp.com/consul/getting-started/install.html
下载完成后只有一个consul.exe文件,硬盘路径下双击运行,查看版本号信息
image-20210602151911375
使用开发模式启动
cmd 窗口输入 consul agent -dev 命令
通过以下地址可以访问 Consul 的首页:http://localhost:8500
image-20210602162654997.png
服务提供者 新建 Module 支付服务 provider8006 cloud-providerconsul-payment8006
POM
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-providerconsul-payment8006</artifactId>
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<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>
<!--日常通用jar包配置-->
<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>
YAML #consul服务端口号 server: port: 8006 spring: application: name: cloud-provider-payment #consul注册中心地址 cloud: consul: host: localhost port: 8500 discovery: #hostname: 127.0.0.1 service-name: ${spring.application.name} 主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication @EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务 public class PaymentMain8006 { public static void main(String[] args) { SpringApplication.run(PaymentMain8006.class, args); } } Controller 我们主要还是想把微服务注册到 Consul 中,所以就写个简单的 Controller
package org.hong.springcloud.controller;
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController @RequestMapping("/payment") @Slf4j public class PaymentController { @Value("${server.port}") private String serverPort;
@GetMapping("/consul")
public String paymentConsul(){
return "springcloud with consul " + serverPort + "\t" + UUID.randomUUID().toString();
}
} 测试 运行 Consul 进入开发者模式,再启动8006,并访问 http://localhost:8500/ui/dc1/services
可以看到 consul-provider-payment 注册到的 Consul 中
image-20210602162814966
服务消费者 新建 Module 消费服务 order81 cloud-consumerconsul-order81
POM
<?xml version="1.0" encoding="UTF-8"?>springcloud org.hong 1.0-SNAPSHOT 4.0.0
<artifactId>cloud-consumerconsul-order81</artifactId>
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<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>
<!--日常通用jar包配置-->
<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>
YAML ###consul服务端口号 server: port: 81 spring: application: name: cloud-consumer-order ####consul注册中心地址 cloud: consul: host: localhost port: 8500 discovery: #hostname: 127.0.0.1 service-name: ${spring.application.name} 主启动 package org.hong.springcloud;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication @EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务 public class OrderMain81 { public static void main(String[] args) { SpringApplication.run(OrderMain81.class, args); } } 配置 Bean package org.hong.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class ApplicationContextBean { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } } Controller package org.hong.springcloud.controller;
import lombok.extern.slf4j.Slf4j; 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.RestController; import org.springframework.web.client.RestTemplate;
@RestController @RequestMapping