微服务+springcloud+springcloud alibaba学习笔记【Eureka服务注册中心】(3/9)

news/2024/5/6 11:16:42/文章来源:https://blog.csdn.net/weixin_43025151/article/details/130037780

Eureka服务注册中心 3/9

    • 1、服务注册与发现
      • 1.1 什么是服务治理:
      • 1.2 什么是服务注册与发现:
      • 1.3 Eureka服务注册与发现
    • 2、单机版eureka
      • 2.1 创建module
      • 2.2改pom依赖
      • 2.3写yml配置文件:
      • 2.4主启动类
      • 2.5 修改服务提供者 cloud-provider-payment8001 模块,
      • 2.6 修改消费者 cloud-customer-order80 模块
      • 2.7 启动三个服务:
    • 3、集群版eureka
      • 3.1 集群原理
      • 3.2 构建Eureka集群
      • 3.3 将Cloud-consumer-order80,Cloud-provider-payment8001模块注册到eureka集群中
    • 4、将Cloud-provider-payment模块也配置为集群模式
      • 4.1 创建新模块Cloud-provider-payment8002
      • 4.2 pom文件,复制8001的
      • 4.3 配置文件复制8001的
      • 4.4 主启动类,复制8001的
      • 4.5 mapper,service,controller都复制一份
      • 4.6 RestTemplate开启负载均衡注解
      • 4.7 修改服务主机名和ip在eureka的web上显示
    • 5、eureka服务发现
      • 5.1 首先添加一个注解,在controller中
      • 5.2 在主启动类上添加一个注解
    • 6、Eureka自我保护
      • 6.1 在 Eureka Server 的模块中的 yml 文件进行配置:
      • 6.2 服务提供者配置
      • 6.3 eureka配置项

1、服务注册与发现

当服务很多时,单靠代码手动管理是很麻烦的,需要一个公共组件,统一管理多服务,包括服务是否正常运行等

上面只有两个微服务,通过 RestTemplate ,是可以相互调用的,但是当微服务项目的数量增大,就需要服务注册中心。目前没有学习服务调用相关技术,使用 SpringCloud 自带的 RestTemplate 来实现RPC。

1.1 什么是服务治理:

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理

在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

1.2 什么是服务注册与发现:

Eureka采用了CS的设计结构,Eureka Server服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。这点和zookeeper很相似

在服务注册与发现中,有一个注册中心。当服务器启动时候,会把当前自己服务器的信息 比如服务地址 通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为便用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))

在这里插入图片描述

1.3 Eureka服务注册与发现

Eureka 官方停更不停用,以后可能用的越来越少。

Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件,以实现中间层服务器的负载平衡和故障转移。

Eureka 分为 Eureka Server 和 Eureka Client及服务端和客户端。Eureka Server为注册中心,是服务端,而服务提供者和消费者即为客户端,消费者也可以是服务者,服务者也可以是消费者。同时Eureka Server在启动时默认会注册自己,成为一个服务,所以Eureka Server也是一个客户端,这是搭建Eureka集群的基础。

==Eureka Client:==一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)。通过注册中心进行访问。是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(roundrobin)负载算氵去的负载均衡器
在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)

==Eureka Server:==提供服务注册服务,各个微服务节,通过配置启动后,会在Eureka Serverc中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点信息,服务节点的信息可以在界面中直观看到。
服务在Eureka上注册,然后每隔30秒发送心跳来更新它们的租约。如果客户端不能多次续订租约,那么它将在大约90秒内从服务器注册表中剔除。注册信息和更新被复制到集群中的所有eureka节点。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)来定位它们的服务(可能在任何区域)并进行远程调用。

服务提供者向注册中心注册服务,并每隔30秒发送一次心跳,就如同人还活着存在的信号一样,如果Eureka在90秒后还未收到服务提供者发来的心跳时,那么它就会认定该服务已经死亡就会注销这个服务。这里注销并不是立即注销,而是会在60秒以后对在这个之间段内“死亡”的服务集中注销,如果立即注销,势必会对Eureka造成极大的负担。这些时间参数都可以人为配置。

Eureka还有自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,所以不会再接收心跳,也不会删除服务。

客户端消费者会向注册中心拉取服务列表,因为一个服务器的承载量是有限的,所以同一个服务会部署在多个服务器上,每个服务器上的服务都会去注册中心注册服务,他们会有相同的服务名称但有不同的实例id,所以拉取的是服务列表。我们最终通过负载均衡来获取一个服务,这样可以均衡各个服务器上的服务。

在这里插入图片描述

2、单机版eureka

  • 消费者端口80,提供者端口8001。

  • Eureka端口7001
    在这里插入图片描述

2.1 创建module

Cloud_eureka_server_7001

在这里插入图片描述

2.2改pom依赖

eureka版本说明:

<!--新版本2020.02-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency><!--旧版本2018-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

pom文件:

在这里插入代码片

2.3写yml配置文件:

server:port: 7001eureka: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/

2.4主启动类

@EnableEurekaServer
最后写主启动类,如果启动报错,说没有配置 DataSource ,就在 主启动类的注解加上 这样的配置:

package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7001 {public static void main(String[] args){SpringApplication.run(EurekaServerMain7001.class, args);log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");}
}

启动测试,访问 7001 端口
在这里插入图片描述

2.5 修改服务提供者 cloud-provider-payment8001 模块,

  1. 在 pom 文件的基础上引入 eureka 的client包,pom 的全部依赖如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud2023</artifactId><groupId>com.tigerhhzz.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Cloud-provider-payment8001</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- 服务注册中心的客户端端 eureka-client --><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.tigerhhzz.springcloud</groupId><artifactId>Cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><!--这个和web要写到一块--><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.2.8</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.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></project>
  1. 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import java.io.Console;/*** @author Administrator*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {public static void main(String[] args){SpringApplication.run(PaymentMain8001.class, args);log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");}
}
  1. yml 文件添加关于 Eureka 的配置:
server:port: 8001spring:application:name: Cloud-provider-payment8001datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址defaultZone: http://localhost:7001/eureka/

2.6 修改消费者 cloud-customer-order80 模块

  1. 在 pom 文件的基础上引入 eureka 的client包,pom 的全部依赖如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud2023</artifactId><groupId>com.tigerhhzz.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Cloud-consumer-order80</artifactId><dependencies><!-- 服务注册中心的客户端端 eureka-client --><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.tigerhhzz.springcloud</groupId><artifactId>Cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></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.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></project>
  1. 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80{public static void main(String[] args){SpringApplication.run(OrderMain80.class,args);log.info("OrderMain80启动成功~~~~~~~~~~~~~~~~~~~");}
}
  1. yml 文件添加关于 Eureka 的配置:
server:port: 80spring:application:name: Cloud-consumer-order80eureka:client:register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://localhost:7001/eureka/

2.7 启动三个服务:

在这里插入图片描述
在这里插入图片描述

3、集群版eureka

3.1 集群原理

  1. 就是pay模块启动时,注册自己,并且自身信息也放入eureka
  2. order模块,首先也注册自己,放入信息,当要调用pay时,先从eureka拿到pay的调用地址
  3. 通过HttpClient调用 ,并且还会缓存一份到本地,每30秒更新一次

在这里插入图片描述

问题:微服务RPC远程服务调用最核心的是什么:

高可用,试想你的注册中心只有一个。onlyone,它出故障了那就呵呵了,会导致整个为服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错

Eureka 集群的原理:

== 相互注册,互相守望。== 每台Eureka服务器都有集群里其他Eureka服务器地址的信息

在这里插入图片描述

3.2 构建Eureka集群

在写配置文件前,修改一下主机的hosts文件

模拟多个 为了不用输出C:\Windows\System32\drivers\etc\hosts 添加如下:127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
  1. 创建 Cloud-eureka-server7002模块
    这也就是第二个 Eureka 服务注册中心,pom 文件和 主启动类,与第一个Cloud-eureka-server7002一致。

     pom文件:粘贴7001的即可
    
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud2023</artifactId><groupId>com.tigerhhzz.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Cloud-eureka-server7002</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</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.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.tigerhhzz.springcloud</groupId><artifactId>Cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></dependency></dependencies></project>
	配置文件:
  1. 修改7001项目的application.yml配置文件

首先修改之前的7001的eureka项目,因为多个eureka需要互相注册

7001项目的application.yml配置文件

server:port: 7001eureka:instance:hostname: eureka7001.com  # eureka 服务器的实例地址  # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址defaultZone: http://eureka7002.com:7002/eureka/
  1. 修改7002项目的application.yml配置文件

         7002也是一样的,只不过端口和地址改一下
    

7002项目的application.yml配置文件

server:port: 7002eureka:instance:hostname: eureka7002.com  # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址defaultZone: http://eureka7001.com:7001/eureka/

eureka.instance.hostname 才是启动以后 本 Server 的注册地址,而 service-url 是 map 类型,只要保证 key:value 格式就行,它代表 本Server 指向了那些 其它Server 。利用这个,就可以实现Eureka Server 相互之间的注册,从而实现集群的搭建。

  1. 主启动类:

复制7001的即可

7001主启动类:

package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7001 {public static void main(String[] args){SpringApplication.run(EurekaServerMain7001.class, args);log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");}
}

7002主启动类:

package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7002 {public static void main(String[] args){SpringApplication.run(EurekaServerMain7002.class, args);log.info("EurekaServerMain7002启动成功~~~~~~~~~~~~~~~~~~~");}
}
  1. 然后启动7001,7002即可

在这里插入图片描述

3.3 将Cloud-consumer-order80,Cloud-provider-payment8001模块注册到eureka集群中

  1. 只需要修改Cloud-consumer-order80,Cloud-provider-payment8001模块的配置文件即可:

Cloud-consumer-order80配置文件

server:port: 80spring:application:name: Cloud-consumer-order80eureka:client:register-with-eureka: truefetch-registry: trueservice-url:
#      defaultZone: http://localhost:7001/eureka/   #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/   #集群版

,Cloud-provider-payment8001模块配置文件

server:port: 8001spring:application:name: Cloud-provider-payment8001datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
  1. 两个模块都修改上面的都一样即可

然后启动两个模块

要先启动7001,7002,然后是pay模块8001,然后是order(80)
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、将Cloud-provider-payment模块也配置为集群模式

4.1 创建新模块Cloud-provider-payment8002

4.2 pom文件,复制8001的

Cloud-provider-payment8002模块的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud2023</artifactId><groupId>com.tigerhhzz.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Cloud-provider-payment8002</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- 服务注册中心的客户端端 eureka-client --><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.tigerhhzz.springcloud</groupId><artifactId>Cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><!--这个和web要写到一块--><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.2.8</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.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></project>

4.3 配置文件复制8001的

端口修改一下,改为8002

Cloud-provider-payment8001模块的配置文件

server:port: 8001spring:application:
#    name: Cloud-provider-payment8001name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版

Cloud-provider-payment8002模块的配置文件

server:port: 8002spring:application:
#    name: Cloud-provider-payment8002name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版

服务名称不用改,用一样的

4.4 主启动类,复制8001的

package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;/*** @author Administrator*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8002 {public static void main(String[] args){SpringApplication.run(PaymentMain8002.class, args);log.info("PaymentMain8002启动成功~~~~~~~~~~~~~~~~~~~");}
}

4.5 mapper,service,controller都复制一份

然后就启动服务即可

此时访问order模块,发现并没有负载均衡到两个pay,模块中,而是只访问8001

虽然我们是使用RestTemplate访问的微服务,但是也可以负载均衡的

4.6 RestTemplate开启负载均衡注解

注意这样还不可以,需要让RestTemplate开启负载均衡注解,还可以指定负载均衡算法,默认轮询

修改Cloud-consumer-order80模块中的config包下面的ApplicationContextConfig类:

package com.tigerhhzz.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;/*** @author tigerhhzz* @date 2023/4/8 22:52*/
@Configuration
public class ApplicationContextConfig {@Bean@LoadBalancedpublic RestTemplate getRestTemplate(){return new RestTemplate();/*RestTemplate提供了多种便捷访问远程http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于rest服务的客户端模板工具集*/}
}

4.7 修改服务主机名和ip在eureka的web上显示

actuator让Eureka显示ip
为了在微服务Eureka控制台能看到我们的某个具体服务是在哪台服务器上部署的,我们需要配置一些内容。

修改 提供者在Eureka 注册中心显示的 主机名:即修改eureka:instance:instance-id:和eureka:instance:prefer-ip-address:

修改Cloud-provider-payment8001模块的配置文件:

server:port: 8001spring:application:
#    name: Cloud-provider-payment8001name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版instance: #重点,和client平行instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名prefer-ip-address: true # 访问路径可以显示ip地址

修改Cloud-provider-payment8002模块的配置文件:

server:port: 8002spring:application:
#    name: Cloud-provider-payment8002name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版instance: #重点,和client平行instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名prefer-ip-address: true # 访问路径可以显示ip地址

在这里插入图片描述

5、eureka服务发现

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。(即我们前面可视化页面的信息)

5.1 首先添加一个注解,在controller中

package com.tigerhhzz.springcloud.controller;import com.tigerhhzz.springcloud.entities.CommonResult;
import com.tigerhhzz.springcloud.entities.Payment;
import com.tigerhhzz.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.List;@RestController   //必须是这个注解,因为是模拟前后端分离的restful风格的请求,要求每个方法返回 json
@Slf4j
public class PaymentController {@Resourceprivate PaymentService paymentService;//服务发现@Resourceprivate DiscoveryClient discoveryClient;@Value("${server.port}")private String serverPort;@PostMapping(value = "/payment/create")//	    注意这里的 @RequestBody  是必须要写的,虽然 MVC可以自动封装参数成为对象,//      但是当消费者项目调用,它传参是 payment 整个实例对象传过来的, 即Json数据,因此需要写这个注解//public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);log.info("****插入结果:" + result);if(result > 0){return new CommonResult(200, "插入数据库成功", result);}return new CommonResult(400, "插入数据库失败", null);}@GetMapping(value = "/payment/{id}")public CommonResult getPaymentById(@PathVariable("id")Long id){Payment result = paymentService.getPaymentById(id);log.info("****查询结果:" + result);if(result != null){return new CommonResult(200, "查询成功", result);}return new CommonResult(400, "没有对应id的记录", null);}@GetMapping("queryAllByLimit")public CommonResult<List<Payment>> queryAllByLimit(@RequestParam(defaultValue = "0") int offset,@RequestParam(defaultValue = "10") int limit) {List<Payment> payment = this.paymentService.queryAllByLimit(offset, limit);return new CommonResult<>(200, "select success, serverPort:" + serverPort, payment);}@GetMapping("/customer/discovery")public Object discovery(){//获得服务清单列表List<String> services = discoveryClient.getServices();for(String service: services){log.info("*****service: " + service);}// 根据具体服务进一步获得该微服务的信息List<ServiceInstance> instances = discoveryClient.getInstances("cloud-provider-service");for(ServiceInstance serviceInstance:instances){log.info(serviceInstance.getServiceId() + "\t" + serviceInstance.getHost()+ "\t" + serviceInstance.getPort() + "\t" + serviceInstance.getUri());}return this.discoveryClient;}
}

5.2 在主启动类上添加一个注解

  • 在主启动类上添加注解:@EnableDiscoveryClient
package com.tigerhhzz.springcloud;import lombok.extern.slf4j.Slf4j;
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;import java.io.Console;/*** @author Administrator*/
@Slf4j
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {public static void main(String[] args){SpringApplication.run(PaymentMain8001.class, args);log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");}
}

打印输出:
在这里插入图片描述

6、Eureka自我保护

在这里插入图片描述
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

禁止自我保护:(如果想)

6.1 在 Eureka Server 的模块中的 yml 文件进行配置:

Cloud-eureka-server7001配置文件:

server:port: 7001eureka:instance:hostname: eureka7001.com  # eureka 服务器的实例地址  # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址defaultZone: http://eureka7002.com:7002/eureka/server: # 与client平行# 关闭自我保护机制,保证不可用该服务被及时剔除enable-self-preservation: falseeviction-interval-timer-in-ms: 2000

Cloud-eureka-server7002配置文件:

server:port: 7002eureka:instance:hostname: eureka7002.com  # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址defaultZone: http://eureka7001.com:7001/eureka/server: # 与client平行# 关闭自我保护机制,保证不可用该服务被及时剔除enable-self-preservation: falseeviction-interval-timer-in-ms: 2000

6.2 服务提供者配置

修改 Eureka Client —Cloud-provider-payment8001模块的 心跳间隔时间:

server:port: 8001spring:application:
#    name: Cloud-provider-payment8001name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版instance: #重点,和client平行instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名prefer-ip-address: true # 访问路径可以显示ip地址# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30sleast-renewal-interval-in-seconds: 1# Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务least-expiration-duration-in-seconds: 2

修改 Eureka Client —Cloud-provider-payment8002模块的 心跳间隔时间:

server:port: 8002spring:application:
#    name: Cloud-provider-payment8002name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版instance: #重点,和client平行instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名prefer-ip-address: true # 访问路径可以显示ip地址# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30sleast-renewal-interval-in-seconds: 1# Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务least-expiration-duration-in-seconds: 2

6.3 eureka配置项

在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。
面是服务续约的两个重要属性:

(1)eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。
默认为90秒
如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
该值至少应该大于leaseRenewalIntervalInSeconds

(2)eureka.instance.lease-renewal-interval-in-seconds

  • leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
    默认30秒

  • eureka.client.registry-fetch-interval-seconds :表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒

  • eureka.server.enable-self-preservation
    是否开启自我保护模式,默认为true。

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。

Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

eureka.server.eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒

Eureka停更说明:2.0后停更了。

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

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

相关文章

GFS的卷类型与集群实验文档

GlusterFS 支持七种卷&#xff0c;即分布式卷、条带卷、复制卷、分布式条带卷、分布式复制卷、条带复制卷和分布式条带复制卷。我们常用的有前五种&#xff0c;今天我们就来看一看这五种卷都有什么优缺点。 一、分布式卷&#xff08;Distribute volume&#xff09; 文件通过 H…

【模型复现】resnet,使用net.add_module()的方法构建模型。小小的改进大大的影响,何大神思路很奇妙,基础很扎实

从经验来看&#xff0c;网络的深度对模型的性能至关重要&#xff0c;当增加网络层数后&#xff0c;网络可以进行更加复杂的特征模式的提取&#xff0c;所以当模型更深时理论上可以取得更好的结果。但是更深的网络其性能一定会更好吗&#xff1f;实验发现深度网络出现了退化问题…

python玄阶斗技--tkinter事件

在前一篇文章中&#xff0c;我们已经了解是tkinter的一些标签的使用&#xff0c;但一个GUI程序除了让别人看到&#xff0c;还要有一些交互操作&#xff0c;实现人机交互的方法我们称为事件&#xff0c;通过事件分为&#xff1a;鼠标事件&#xff0c;键盘事件和窗口事件。接下来…

Neo4j初学者使用记录(在更)

打开Neo4j cmdR 输入neo4j console 浏览器中输入框中网址&#xff1a;http://localhost:7474/即可打开 新建库 服务器版需要更改配置文件&#xff0c;若neo4j服务正在运行&#xff0c;则按Ctrlc&#xff0c;停止该服务。 配置完后&#xff0c;再重新开启服务&#xff0c;刷新…

如何利用ventoy制作Linux to go (把deepin放到U盘里)

准备工作 最新版本 – 深度科技社区 (deepin.org) deepin镜像官方下载即可 Releases ventoy/vtoyboot GitHub ventoy启动插件选择1.0.29版本 Downloads – Oracle VM VirtualBox VirtualBox虚拟机官网 ventoy下载 VentoyRelease (lanzoui.com) 选择下载1.0.29版本 vento…

第五十八章 线段树(一)

第五十八章 线段树&#xff08;一&#xff09;一、树状数组的缺陷二、线段树的作用三、线段树的基本构成1、节点定义2、线段树的结构四、线段树的重要函数1、构造线段树——bulid函数2、查询区间——query函数3、单点修改——modify函数五、例题一、树状数组的缺陷 在前面两个…

对于电商行业来讲,真正决定它的并不是规模,而是载体

纵然是在现在这样的情况之下&#xff0c;我们依然无法用「格局已定」来形容和阐述现在的电商市场格局。这一点&#xff0c;我们可以从以抖音、快手为代表的电商新势力的崛起当中&#xff0c;看出一丝端倪。对于电商行业来讲&#xff0c;真正决定它的并不是规模&#xff0c;而是…

Dart中的异步

一 事件循环 flutter 就是运行在一个root isolate 中 程序只要运行起来&#xff0c;就有一个事件循环一直在运行 &#xff0c;直至程序退出。 EventLoop 先从mrcro 对列中取任务&#xff0c;取完任务再去 event 队列中取任务。队列任务是FIFO。 二 认识Future abstract clas…

[JavaEE]----Spring03

文章目录Spring_day031&#xff0c;AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念2&#xff0c;AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知…

C++内存管理(new和delete)

目录 1. new/delete操作内置类型 2. new和delete操作自定义类型 3. operator new与operator delete函数 4 .new和delete的实现原理 1 .内置类型 2 .自定义类型 new的原理 delete的原理 new T[N]的原理 delete[]的原理 5. 定位new表达式(placement-new) 6. malloc/f…

使用Process Explorer和Clumsy定位软件高CPU占用问题

目录 1、问题描述 2、使用Process Explorer初步找到CPU占用高的原因 3、使用Clumsy工具在公司内网环境复现了问题 4、根据Process Explorer中的函数调用堆栈&#xff0c;分析源码&#xff0c;最终找出了问题 5、总结 在排查项目客户的视频图像闪烁问题时&#xff0c;无意中…

Centos7安装部署Jenkins

Jenkins简介&#xff1a; Jenkins只是一个平台&#xff0c;真正运作的都是插件。这就是jenkins流行的原因&#xff0c;因为jenkins什么插件都有 Hudson是Jenkins的前身&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控程序重复的工作&#xff0c;Hudson后来被…

JavaScript基础-02

常量&#xff08;字面量&#xff09;&#xff1a;数字和字符串 常量也称之为“字面量”&#xff0c;是固定值&#xff0c;不可改变。看见什么&#xff0c;它就是什么。 常量有下面这几种&#xff1a; 数字常量&#xff08;数值常量&#xff09;字符串常量布尔常量自定义常量…

【MATLAB数学建模编程实战】Kmeans算法编程及算法的简单原理

欢迎关注&#xff0c;本专栏主要更新MATLAB仿真、界面、基础编程、画图、算法、矩阵处理等操作&#xff0c;拥有丰富的实例练习代码&#xff0c;欢迎订阅该专栏&#xff01;&#xff08;等该专栏建设成熟后将开始收费&#xff0c;快快上车吧~~&#xff09; 【MATLAB数学建模编…

[LeetCode周赛复盘] 第 340 场周赛20230409

[LeetCode周赛复盘] 第 340 场周赛20230409 一、本周周赛总结二、 6361. 对角线上的质数1. 题目描述2. 思路分析3. 代码实现三、6360. 等值距离和1. 题目描述2. 思路分析3. 代码实现四、6359. 最小化数对的最大差值1. 题目描述2. 思路分析3. 代码实现五、 6353. 网格图中最少访…

ROS实践06 自定义消息类型

文章目录运行环境&#xff1a;思路&#xff1a;1.1 定义.msg文件1)功能包下新建 msg 目录&#xff0c;添加文件 Person.msg2)修改package.xml3)修改CMakeLists.txt2.1 自定义消息调用(C)1&#xff09;编译后修改includePath2&#xff09;发布方实现2.1修改CMakeLists.txt2.3运行…

【OpenCV-Python】cvui 之 trackbar

CVUI 之 trackbar cvui::trackbar() 渲染一个 trackbar&#xff0c; 可以左右拖动或点击对数字进行增加或减少的调整。 不使用离散间隔 使用离散间隔 Python import numpy as np import cv2 import cvuidef trackbar_test():WINDOW_NAME Trackbar-Test# 创建画布frame np.z…

【Python童年游戏】满满的回忆杀—那些年玩过的童年游戏你还记得吗?那个才是你的菜?看到第一个我就泪奔了(致我们逝去的青春)

导语 滴一一学生卡&#x1f64c; 结伴上车的学生仔子们 用笑声打破车厢的沉默 大人眼里的晚高峰 是给放学后快乐&#x1f600;时光的加时 下车的学生匆匆起身带起 一阵熟悉的栀子香于&#x1f493; 是关于校园的记忆 开始零零散散地闪现 放学后集合的秘密基地/跟着城…

LVGL v8学习笔记 |12 - 移植LVGL 8.3到ESP32C3开发板(ST7789)

一、移植前的准备 1. 基础工程 ESP32-IDF开发笔记 | 03 - 使用SPI外设驱动ST7789 SPILCD2. lvgl源码 https://github.com/lvgl/lvgl下载最新发布的 8.3.6 版本:https://github.com/lvgl/lvgl/releases/ 二、移植lvgl 1. 复制lvgl源码到工程中 将下载的 lvgl-8.3.6 文件夹直…

JSON数据遍历之for-in

JSON数据遍历之for-in object 本身就是无对象的集合&#xff0c;因此在用 for-in 语句遍历对象的属性时&#xff0c;遍历出的属性顺序与对象定义时不同。 W3C标准 根据 ECMA-262&#xff08;ECMAScript&#xff09;第三版中描述&#xff0c;for-in 语句的属性遍历的顺序是由对…