SpringCloud学习笔记(上):服务注册与发现:Eureka、Zookeeper、Consul+负载均衡服务调用:Ribbon
壹、零基础
一、微服务架构零基础理论入门
SpringCloud=分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶。



二、从2.2.x和H版开始说起
springboot版本选择:
git源码地址:https://github.com/spring-projects/spring-boot/releases/
SpringBoot2.0新特性:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release
springcloud版本选择:
git源码地址:https://github.com/spring-projects/spring-cloud
官网:https://spring.io/projects/spring-cloud
官网看cloud版本
springcloud和springboot之间依赖关系:https://spring.io/projects/spring-cloud#overview

三、关于Cloud各种组件的停更/升级/替换
服务注册中序:Eureka(挂)。zookeeper。Consul。Nacos(百万级推荐)。
服务调用1:Ribbon。LoadBalancer。
服务调用2:Feign(挂)。OpenFeign。
服务降级:Hystrix(挂)。resilience4j。sentienl(推荐)。
服务网关:Zuul(挂)。Zuul2(未出)。gateway(推荐)。
服务配置:Config(挂)。Nacos(推荐)。
服务总线:Bus(挂)。Nacos(推荐)。
参考资料:
1. Spring Cloud:https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/
2. Spring Cloud中文文档:https://www.bookstack.cn/read/spring-cloud-docs/docs-index.md
3. Spring Boot:https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/htmlsingle/
四、微服务架构编码构建
4.1 引入依赖





<!-- 统一管理jar包版本 --><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version><mysql.version>5.1.47</mysql.version><druid.version>1.1.16</druid.version><mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version></properties>
<!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version --><dependencyManagement><dependencies><!--spring boot 2.2.2--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.2.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--spring cloud Hoxton.SR1--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR1</version><type>pom</type><scope>import</scope></dependency><!--spring cloud alibaba 2.1.0.RELEASE--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.spring.boot.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><optional>true</optional></dependency></dependencies></dependencyManagement>
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.2.1.RELEASE</version><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin></plugins></build>
DependencyManagement和Dependencies的区别:
<DependencyManagement>是父类定义的坐标版本号,用在父工程,类似于规范将全工程的版本统一,只负责定义,而不负责引入实现。真正引入依赖的是子类<dependencies>定义的版本号。如果子类没指定版本号,默认是用父类的。如果子类指定了版本号,则版本号用子类指定的(如果不在子项目中声明依赖,不会从父项目中继承。只要在子项目中写了该依赖项,并且没有指定具体的版本,才会从父项目中继承该项,并且version和scope都读取自父pom)。
maven中跳过单元测试:

4.2 支付模块构建
1.建module:右键项目新建Module

2.改POM
<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><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. 写YML
在cloud-provider-payment8001的resources下创建application.yml文件,注意要变成绿色树叶:
server:port: 8081spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&usrSSL=falseusername: rootpassword: 111111mybatis:mapper-locations: classpath:mapper/*.xml #在mapper包下创建.xml配置文件type-aliases-package: com.atguigu.springcloud.entities #entities下创建实体类
4. 主启动
在src/main/java/com/atguigu/springcloud包下创建PaymentMain8001类,加上@SpringBootApplication作为主启动类:
@SpringBootApplication
public class PaymentMain8001 {public static void main(String[] args){SpringApplication.run(PaymentMain8001.class,args);}
}
5. 业务类
5.1 建表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
5.2 entities实体类
在java/com/atguigu/springcloud下创建entities包,在其下创建Payment类:
主实体Payment代码:
public class Payment implements Serializable {private Long id;private String serial;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getSerial() {return serial;}public void setSerial(String serial) {this.serial = serial;}public Payment(Long id, String serial) {this.id = id;this.serial = serial;}public Payment() {}
}
Json封装体CommonResult
在entities包下创建CommonResult类:
public class CommonResult<T> {private Integer code;private String message;private T data;public CommonResult(Integer code,String message){this(code,message,null);}public CommonResult(Integer code, String message, T data) {this.code = code;this.message = message;this.data = data;}public CommonResult() {}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}
1. @Data是一个Lombok注解,用于自动生成Java类的常见方法,如getter、setter、toString、equals和hashCode方法。
2. this(code, message, null)表示调用当前类的另一个构造函数CommonResult(Integer code, String message, Object data),并传递参数code、message和null。
3. @AllArgsConstructor是Lombok注解之一,用于自动生成一个包含所有参数的构造函数。
5.3 dao
创建dao包,在其下创建PaymentDao接口,记得写@Mapper注解:
@Mapper
public interface PaymentDao {public int create(Payment payment);public Payment getPaymentById(@Param("id") Long id);
}
mybatis的映射文件:
在resources下创建mapper包,创建PaymentMapper.xml映射文件:
1. parameterType是用来指定传入SQL语句的参数类型。
2. resultMap用来指定查询结果映射到哪个Java对象上。
3. column是数据库字段,property是java对象属性。
4.keyProperty:用于指定自动生成的主键值要被设置到Java实体类的哪个属性上。
resultMap映射属性,用于防止命名不规范造成错误:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.springcloud.dao.PaymentDao"><insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">insert into payment(serial) values(#{serial});</insert><resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment"><id column="id" property="id" jdbcType="BIGINT"/><id column="serial" property="serial" jdbcType="VARCHAR"/></resultMap><select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">select * from payment where id=#{id};</select>
</mapper>
5.4 service
在springcloud下创建service包,创建PaymentService接口:
public interface PaymentService{public int create(Payment payment);public Payment getPatmentById(@Param("id") Long id);
}
1. @Param注解的作用是给方法参数起别名,@Param注解的作用是给方法参数起别名。@Param("id")表示给方法参数id起别名为"id"。这样在SQL映射文件中可以使用#{id}来引用这个参数。
创建PaymentServiceImpl实现类,记得写@Service注解
1. @Resource注解是用来标记一个需要依赖注入的对象。可以根据名称进行依赖注入,也可以根据类型进行依赖注入。
@Service
public class PaymentServiceImpl implements PaymentService {@Resourceprivate PaymentDao paymentDao;public int create(Payment payment) {return paymentDao.create(payment);}public Payment getPatmentById(Long id) {return paymentDao.getPaymentById(id);}
}
5.5 controller
在springcloud下创建controller包,然后创建PaymentController类:
1. @GetMapping注解用于将HTTP的GET请求映射到相应的处理方法上。
2. @PathVariable注解用于将URL路径中的变量值绑定到方法参数上。
@RestController
public class PaymentController {@Resourceprivate PaymentService paymentService;@PostMapping(value="/payment/create")public CommonResult create(Payment payment){System.out.println(payment.getSerial());int result = paymentService.create(payment);if(result>0){return new CommonResult(200,"插入数据库成功",result);}else{return new CommonResult(444,"插入数据库失败",null);}}@GetMapping(value="/payment/get/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.getPatmentById(id);if(payment != null){return new CommonResult(200,"查询成功",payment);}else{return new CommonResult(444,"没有对应记录,查询ID:"+id,null);}}
}
5.6 测试
启动启动类,在地址栏输入localhost:8001/payment/get/31
浏览器不适合发post请求,因此去postman发请求,id是自增的,只需要发送serial即可:


4.3 热部署
Devtools热部署,代码改动,自动重启。
第1步:在cloud-provider-payment8001添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional>
</dependency>
第2步:父工程cloud2020添加插件
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.2.1.RELEASE</version><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin></plugins></build>
第3步:开启自动编译权限

第4步:更新值,开启热注册

输入快捷键:ctrl + shift + alt + /

第5步:重启
(失败)测试:同样是PaymentMain8001启动,然后进入到cloud-provider-payment8001下的controller,更改CommonResult为CommonResult<Payment>,会实时刷新(失败)。
4.4 消费者订单模块
1. 建module
名字:Cloud-consumer-order80,src下有main和test,main下有java和resource

2. 改pom
web、acuator是图形化的监控展现,要先加mybatis的驱动运行,之后可以删除mybatis驱动,不然.yml会变不成绿叶:
<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><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency>
</dependencies>
3. 写YML
在resources下建application.yml,设置端口80
server:port: 81
4. 主启动
在java下创建com.atguigu.springcloud.OrderMain80类
@SpringBootApplication
public class OrderMain81 {public static void main(String[] args){SpringApplication.run(OrderMain81.class,args);}
}
5. 业务类
5.1 entities复制payment8001的
RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集。

5.2 创建springcloud下的config包,在包下创建ApplicationContextConfig类:
@Configuration
public class ApplicationContextConfig{@Beanpublic RestTemplate getRestTemp(){return new RestTemplate();}
}
5.3 在controller包下创建OrderController类:
@RestController
@Slf4j
public class OrderController{public static final String PAYMENT_URL = "http://localhost:8081";@Resourceprivate RestTemplate restTemplate;@PostMapping("/consumer/payment/create")public CommonResult<Payment> create(Payment payment){return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);}@GetMapping("/consumer/payment/get/{id}")public CommonResult<Payment> getPayment(@PathVariable("id") Long id){return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);}
}

但此时调用create方法会出现插入值为空的情况,记得要在cloud-provider-payment8001的controller下的PaymentController类中加入@RequestBody注解:

@RequestBody注解用于将HTTP请求的请求体部分映射到方法的参数上。
新版的Dashboard叫作services
4.5 重构
新建一个cloud-api-commons模块,作为通用封装类:

在模块下引入依赖:
<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>
在模块的java目录下建com.atguigu.springcloud.entities包,直接将entities粘贴在下面:
点击右边的Maven,选择刷新出现cloud-api-commons,进入Lifecycle点击clean点击install即可。
删除掉原先的entities包
将下面依赖粘贴在删掉entities包的模块之下:
<dependency><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version>
</dependency>
贰、初级
五、Eureka服务注册与发现
7001、7002模拟的是Eureka服务器,81模拟消费者,8081和8082模拟生产者。
5.1 基础知识



5.2 服务端安装
1. 建module
ArtifactId:cloud-eureka-server7001,com.atguigu.springcloud
2. 改POM
<dependencies>
<!--eureka-server-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</deoendency>
<dependency><groupId>org.atguigu.springcloud</groupId><artifactId>cloud-api-common</artifactId><version>${project.version}</version>
</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.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. 写YML
在resources下创建application.yml
server:port: 7001
eureka:instance:hostname: localhost #eureka服务端实例名称client:#false表示不向注册中心注册自己register-with-eureka: false#false表示自己端就是注册中心,我的职责就是维护服务实例,不需要检索服务fetch-registry: falseservice-url:#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4. 主启动
创建EurekaMain7001作为启动类:
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001{public static void main(String[] args){SpringApplication.run(EurekaMain7001.class,args);}
}
如果成功输入localhost:7001后出现下面字样:

5.3 支付微服务8081入驻进eurekaServer
在8081的Pom中引入:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在application.yml文件中增加如下代码:
eureka:client:#表示是否将自己注册进Eurekaserver默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡。fetchRegistry: trueservice-url:defaultZone: http://localhost:7001/eureka
在启动类添加注解:@EnableEurekaClient
如果成功,Instances区域会出现CLOUD-PAYMENT-SERVICE这一新的Instances:

5.4 订单微服务81入驻进eurekaServer
在Pom中加入如下代码:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在YML中加入如下代码:
eureka:client:register-with-eureka: truefetchRegistry: trueservice-url:defaultZone: http://localhost:7001/eureka
在启动类中加入如下代码:@EnableEurekaClient
如果成功出现如下2个:

register-with-eureka为false表示不让入驻,为true表示让入驻。
5.5 集群原理说明
Eureka Server:服务注册,将服务信息注册进服务中心。服务发现,从注册中心上获取服务信息。实质,存key服务名 取 value调用地址。
先启动eureka注册中心。启动服务提供者payment支付服务。支付服务启动后会把自身信息(如服务地址以别名方式注册进eureka)。消费者order服务在需要调用接口时,使用服务别名去注册中心获取实际的RPC远程调用地址。消费者或者调用地址后,底层实际是利用HttpClient技术实现远程调用。消费者获取服务地址后会缓存在本地jvm内存中,默认每隔30秒更新一次服务调用地址。
Eureka具有高可用特点,可搭建Eureka注册中心集群,实现负载均衡+容错故障。避免单点故障。互相注册,相互守望。
5.6 集群环境构建
建Module:cloud-eureka-server7002
Pom:直接复制7001
YML:建application.yml
主启动类:EurekaMain7002,用7001的注解
修改配置:C:\Windows\System32\drivers\etc路径下的hosts文件。
![]()
修改7001的.yml,修改hostname和defaultZone:
server:port: 7001
eureka:instance:hostname: eureka7001.com #eureka服务端实例名称client:#false表示不向注册中心注册自己register-with-eureka: false#false表示自己端就是注册中心,我的职责就是维护服务实例,不需要检索服务fetch-registry: falseservice-url:#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址defaultZone: http://eureka7002.com:7002/eureka/
修改7002的.yml文件:
server:port: 7002
eureka:instance:hostname: eureka7002.com #eureka服务端实例名称client:#false表示不向注册中心注册自己register-with-eureka: false#false表示自己端就是注册中心,我的职责就是维护服务实例,不需要检索服务fetch-registry: falseservice-url:#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址defaultZone: http://eureka7001.com:7001/eureka/
输入eureka7002.com:7002==127.0.0.1:7002和eureka7001.com:7001==127.0.0.1能见到eureka首页:

输入
locahost:7002能指向7001,locahost:7001能指向7002算是成功:


5.7 订单支付两微服务注册进Eureka集群
YML:在8081的eureka下添加:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
YML:在81的eureka下添加:
eureka:client:register-with-eureka: truefetchRegistry: trueservice-url:defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
启动:
先要启动EurekaServer,7001/7002服务
再启动服务提供者provider,8081
再启动消费者,81
输入http://localhost:81/consumer/payment/get/31,如果查询成功即可
测试:

eureka7001.com:7001可以看到81和8081注册进入

eureka7002.com:7002同样也可以看到
5.8 支付微服务集群配置
建Module:创建cloud-provider-payment8082
改Pom:把8081粘贴入8082
写YML:把8081的粘贴入8082,改一个端口号
主启动:建PaymentMain8082把8081的启动类复制过来,把resource下的mapper包粘贴到8082,把com包直接粘贴到8082。
改controller:修改8001和8002加入如下内容:
@Value("${server.port}")
private String serverPort;
return new CommonResult(200,"插入数据库成功,serverPort"+serverPort,result);
return new CommonResult(200,"查询成功,serverPort"+serverPort,payment);
启动顺序:7001、7002、8081、8082、81
测试:eureka7001.com:7001,eureka7002.com:7002,localhost:81/consumer/payment/get/31

发现bug:订单服务访问地址是写死的。

此时会报错,因为IDEA不知道是这个地址下的哪台服务器提供服务。
使用@LoadBalanced注解赋予RestTemplate负载均衡的能力,注解写在config包的ApplicationContextConfig下:

此时访问localhost:81/consumer/payment/get/31,端口号会在8081和8082之间来回切换:


5.9 actuator微服务信息完善
加上instance: instance-id和prefer-ip-address: true(访问路径显示ip地址)


5.10 服务发现Discovery
在8081的controller的PaymentController类上修改:
@Slf4j
@RestController
public class PaymentController {@Resourceprivate DiscoveryClient discoveryClient;@GetMapping(value="/payment/discovery")public Object discovery(){List<String> services = discoveryClient.getServices();for(String element : services){log.info("*****element: "+element);}List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");for(ServiceInstance instance : instances){log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());}return instances;}
}

5. 11 Eureka自我保护理论知识

概括:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务器剔除。

5.12 禁止自我保护
在7001的yml文件中的eureka下,加下列代码:
server:#关闭自我保护机制,保证不可用服务被及时踢除enable-self-preservation: falseeviction-interval-timer-in-ms: 2000
![]()

测试:先看8081是否存在,关闭8081,看卡是否立刻删除。
Eureka停更说明
六、Zookeeper服务注册与发现
6.1 Zookeeper的安装
下载zookeeper-3.4.9,下面是安装地址
https://archive.apache.org/dist/zookeeper/
在Linux虚拟机中,创建/opt/module目录,把zookeeper的gz压缩包放到该目录下。
然后解压该压缩包到该目录:
tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
然后修改配置:
将/opt/module/zookeeper-3.4.10/conf这个路径下的zoo.sample.cfg修改为zoo.cfg:
mv zoo_sample.cfg zoo.cfg
在/opt/module/zookeeper-3.4.10目录创建zkData文件夹:
mkdir zkData
打开zoo.cfg文件,修改dataDir路径:
vim zoo.cfg
修改如下内容:
dataDir=/opt/module/zookeeper-3.4.10/zkData
启动Zookeeper服务
输入:sudo /opt/module/zookeeper-3.4.9/bin/zkServer.sh start
进入Zookeeper
输入:sudo /opt/module/zookeeper-3.4.9/bin/zkCli.sh
退出Zookeeper
输入:quit
关闭Zookeeper服务:
sudo /opt/module/zookeeper-3.4.9/bin/zkServer.sh stop
6.2 项目环境配置

在/opt/module/zookeeper-3.4.9/bin目录下输入:
sudo systemctl stop firewalld 关闭防火墙。
sudo systemctl status firewalld检查防火墙是否关闭。
确保虚拟机能和windows ping通

建module:cloud-provider-payment8004
pom:
<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.cloud</groupId><artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
YML:
server:port: 8004
#服务别名 — — — — 注册zookeeper到注册中心名称
spring:application:name: cloud-provider-paymentcloud:zookeeper:connect-string: 192.168.182.157:2181
启动类:
com.atguigu.springcloud.PaymentMain8004
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {public static void main(String[] args) {SpringApplication.run(PaymentMain8004.class,args);}
}
服务类:
springcloud下建controller包,PaymentController
@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@RequestMapping(value="/payment/zk")public String paymentzk(){return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();}
}
然后启动Zookeeper服务,进入zookeeper
输入:sudo /opt/module/zookeeper-3.4.9/bin/zkServer.sh start
输入:sudo /opt/module/zookeeper-3.4.9/bin/zkCli.sh
输入:get /zookeeper
版本冲突问题:
<dependency>
<!--添加zookeeper3.4.9版本--><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.9</version>
<!--先排除自带的zookeeper3.5.3--><exclusions><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency>
然后点击启动。
测试localhost:8004/payment/zk,如果每次刷新后面一串数字会变则成功:


把json串赋值到tool.lu/json看得到信息则成功:

6.3 临时还是持久节点
用的是临时的,关闭8004一段时间,zookeeper会踢掉。重新启动,流水号会改变。
6.4 订单服务注册进zookeeper
module:cloud-consumerzk-order81。
POM:复制8004,见上节。
YML:
server:port: 81
#服务别名 — — — — 注册zookeeper到注册中心名称
spring:application:name: cloud-consumer-ordercloud:#注册到zookeeper地址zookeeper:connect-string= 192.168.182.157:2181
启动类:
@SpringBootApplication
@EnableDiscoveryClient
public class OrderZKMain81 {public static void main(String[] args) {SpringApplication.run(OrderZKMain81.class,args);}
}
config:
@Configuration
public class ApplicationContextConfig {@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}
}
controller:
@RestController
@Slf4j
public class OrderZKController {public static final String INVOKE_URL="http://cloud-provider-payment";@Resourceprivate RestTemplate restTemplate;@GetMapping(value="/consumer/payment/zk")public String paymentInfo(){String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);return result;}
}
测试:
![]()

七、Consul服务注册与发现
7.1 Consul简介


7.2 安装并运行Consul
下载地址:
https://developer.hashicorp.com/consul/downloads
![]()
点击地址栏,输入cmd,输入consul --version,再输入consul agent -dev
输入http://localhost:8500会进入界面,看到勾勾:

7.3 服务提供者注册进Consul
module:cloud-providerconsul-payment8006
pom:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</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.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>
yml:
server:port: 8006spring:application:name: consul-provider-payment#consul注册中心地址
cloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}
启动类:
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {public static void main(String[] args) {SpringApplication.run(PaymentMain8006.class,args);}
}
业务类:复制8004,稍加修改
@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@RequestMapping(value="/payment/consul")public String paymentzk(){return "springcloud with consul: "+serverPort+"\t"+ UUID.randomUUID().toString();}
}
测试类:启动

7.4 服务消费者注册进Consul
module: cloud-consumerconsul-order81
pom:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</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.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>
yml:
server:port: 80spring:application:name: cloud-consumer-order#consul注册中心地址
cloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}
主启动类:

配置Bean:

Controller:

验证测试:启动

访问测试地址:

7.5 三个注册中心异同点

CAP:

AP是Eureka,是保证一致性。
不同网络分区数据同步失败,为了保证可用性,允许可以返回旧值,所以是违背了一致性要求。

CP是Zookeeper和Consul,是数据要一致,不一致就挂报错。
八、Ribbon负载均衡服务调用
8.1 Ribbon入门介绍
1.先恢复环境EurekaMain7002,PaymentMain8002,OrderMain81,PaymentMain8081,EurekaMain7001。

基本介绍:

能做什么:

集中式:

进程内:

8.2 Ribbon的负载均衡和Rest调用

相关文章:
SpringCloud学习笔记(上):服务注册与发现:Eureka、Zookeeper、Consul+负载均衡服务调用:Ribbon
壹、零基础 一、微服务架构零基础理论入门 SpringCloud分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶。 二、从2.2.x和H版开始说起 springboot版本选择: git源码地址:https://github.…...
JavaPTA练习题 7-3 身体质量指数(BMI)测算
体重是反映和衡量一个人健康状况的重要标志之一,过胖和过瘦都不利于健康,BMI(身体质量指数)计算方法:体重(以千克为单位)除以身高(以米为单位)的平方。中国成人正常的BMI…...
类的属性和方法(java)
类和对象的使用 创建类,设计类的成员创建类的对象通过“对象.属性”或“对象.方法”调用对象的结构 代码 public class Per {public static void main(String[] args) {// TODO Auto-generated method stub//创建Person类的对象Person p1 new Person();//Scanne…...
C++模拟实现——list
一、成员变量及其基本结构 1.基本结构模型 本质是一个带头双向循环列表,将节点进行封装,并且为了方便使用,进行重定义 2.节点的封装定义 template<class T>//定义节点struct list_node{list_node<T>* _prev;list_node<T>…...
FPGA的音乐彩灯VHDL流水灯LED花样,源码和视频
名称:FPGA的音乐彩灯VHDL流水灯LED 软件:Quartus 语言:VHDL 代码功能: (1)设计一彩灯控制电路,按要求控制8路(彩灯由发光 二极管代替,受实验箱限制,多路同…...
企业知识库软件,快速构建企业知识分享与团队协同的软件
企业知识库是一种特殊的在线协同文档工具,支持包括FAQ、文档、视频、知识图谱等。从本质上讲,它是基于企业知识库软件从而实现内部或外部知识的沉淀、集合、更新、共享等,能为员工或客户提供常见问题的标准回答。 今天我就基于HelpLook &…...
Java,输出一个10行的杨辉三角
据图可以发现,杨辉三角是每行的首元素和末元素都为1,中间的元素都是等于它上面的元素加上左上角的元素。 首先,先完成二数组的创建和初始化,第一行的长度为一,第二行的长度为二……以此类推。所以,外元素的…...
Java版Http请求post和get两种调用实现
在实际项目中常涉及到相互调用,对于http接口的调用,需要经过建立连接,拼接参数,调用等步骤,记录下来,方便查看。 第一步、引入jar包 pom中引入apache的httpclient包 <dependency><groupId>c…...
yjs demo: 多人在线协作画板
基于 yjs 实现实时在线多人协作的绘画功能 支持多客户端实时共享编辑自动同步,离线支持自动合并,自动冲突处理 1. 客户端代码(基于Vue3) 实现绘画功能 <template><div style"{width: 100vw; height: 100vh; over…...
虹科分享 | 赋能物流机器人:CANopen通信如何发挥重要作用?
现代物流领域迅速融入了技术进步,特别是随着自主机器人的兴起,这一趋势越发明显。确保这些机器人在复杂的仓库环境中精确运行的一个关键方面是CANopen通信协议。该协议集成了各种组件(电机、传感器、摄像头和先进的电池系统)&…...
南丁格尔玫瑰图
目录 由来 效果图 echarts官网找相似图 将南丁格尔玫瑰图引进html页面中 引入echarts 准备容器 初始化echarts实例对象 指定配置项和数据(官网给的option) 将配置项给echarts 自定义南格丁尔玫瑰图 修改颜色 修改玫瑰图大小 修改图的模式为半…...
vue 大文件切片下载
前提是你上传的时候也是切片上传,下载的时候后端给你返回的是一个文件id的数组,如果是你就可以用下面的方法 // 循环下载文件 // id是每个文件的id type 是一个类型,我传入是应为给不同的组件赋值getFile(id, type) {// 通过wen文件id去获取…...
2023年“绿盟杯”四川省大学生信息安全技术大赛
pyfile 先check源码,没什么发现,接着进行目录扫描,扫到路径 /download 下载备份文件得到 www.zip,解压得到app.py 大致审一下代码: 在read目录下给file传参进行请求,如果这个东西存在就会读取出来 这里…...
YOLOv8改进实战 | 更换主干网络Backbone(二)之轻量化模型GhostnetV2
前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…...
【C++代码】二叉搜索树的最近公共祖先,二叉搜索树中的插入操作,删除二叉搜索树中的节点--代码随想录
题目:二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大&a…...
【ArcGIS微课1000例】0075:将AutoCAD(Dwg、Dxf)文件转换为shp、KML(kml、kmz)文件
文章目录 1. 加载DWG2. 导出为shp3. 投影变换4. 转为kml1. 加载DWG 打开ArcMap,点击添加符号: 选择地形图dwg数据,全选图层,也可以选择需要的图层。 提示位置的空间参考,点击确定即可。 加载效果。 2. 导出为shp 接下来我们演示将面状数据转为shp,选择Polygon图层,右键…...
Unigui中获取手机特征码
在Delphi Unigui中,您可以使用TUniDeviceInfo类来读取设备的一些基本信息,例如设备的操作系统版本、设备名称和分辨率等。但是,TUniDeviceInfo类并不提供设备的特征码信息。 如果您想要获取设备的特征码信息,您可以使用JavaScrip…...
Github Actions实现Spring Boot自动化部署(第二弹)
Github Actions实现Spring Boot自动化部署(第二弹) 前言 今天就来讲述一下如何使用GitHub结合Actions实现Spring Boot程序从提交代码到打包、容器化、部署全过程自动化。首先咱们得现有一个能够在本地运行的Spring Boot程序,并且在Githu…...
【Python机器学习】sklearn.datasets分类任务数据集
如何选择合适的数据集进行机器学习的分类任务? 选择合适的数据集是进行任何机器学习项目的第一步,特别是分类任务。数据集是机器学习任务成功的基础。没有数据,最先进的算法也无从谈起。 本文将专注于sklearn.datasets模块中用于分类任务的数据集。这些数据集覆盖了各种场…...
华为OD 数组去重和排序(100分)【java】A卷+B卷
华为OD统一考试A卷B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入ÿ…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...
mq安装新版-3.13.7的安装
一、下载包,上传到服务器 https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.13.7/rabbitmq-server-generic-unix-3.13.7.tar.xz 二、 erlang直接安装 rpm -ivh erlang-26.2.4-1.el8.x86_64.rpm不需要配置环境变量,直接就安装了。 erl…...
LangChain + LangSmith + DeepSeek 入门实战:构建代码生成助手
本文基于 Jupyter Notebook 实践代码,结合 LangChain、LangSmith 和 DeepSeek 大模型,手把手演示如何构建一个代码生成助手,并实现全流程追踪与优化。 一、环境准备与配置 1. 安装依赖 pip install langchain langchain_openai2. 设置环境变…...
Go 语言中的内置运算符
1. 算术运算符 注意: (自增)和--(自减)在 Go 语言中是单独的语句,并不是运算符。 package mainimport "fmt"func main() {fmt.Println("103", 103) // 13fmt.Println("10-3…...
