什么是服务治理
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册
什么是服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持 心跳链接 。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息(比如:服务地址、通讯地址等)以别名方式注册到注册中心中。另一方(消费者/服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
下左图是Eureka系统架构,右图是Dubbo系统架构

Eureka Server提供服务注册中心
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
Eureka Client通过注册中心进行访问,是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中表把这个服务节点移除(默认90秒)
Eureka Client分为两个角色,分别是:Application Service(Service Provider)和Application Client(Service Consumer)
Application Service
服务提供方,是注册到Eureka Server中的服务。
Application Client
服务消费方,通过Eureka Server发现服务,并消费。
构建项目
服务:cloud-consumer-order80 (服务消费者)
cloud-provider-payment8001(服务提供者)、cloud-provider-payment8002(服务提供者)[8001和8002是同一个服务的集群]
注册中心(集群):cloud-eureka-server7001、cloud-eureka-server7002
公共commom:cloud-api-commons(存放公共的实体类、工具类...)
1.IDEA新建project
1.1New Project
1.2工程总名称
1.3Maven
1.4工程名称
1.5编码设置
1.6注解生效
1.7.编译版本
1.8.file type过滤
1.9.pom文件
1.10.父工程install
2.创建服务模块-cloud-provider-payment8001
2.1创建modul
2.2pom文件
<?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>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8001</artifactId> <dependencies> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <!--热部署-代码改变自动编译--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- eureka客户端服务 可以作为服务注册到注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <!--热部署--> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> </project>
2.3配置文件yml
server: port: 8001 spring: application: name: cloud-payment-service #将会作为注册到注册中心的服务名称 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 573875306 mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: com.atguigu.springcloud.entities eureka: client: register-with-eureka: true #表识向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息,默认为true。单节点无所谓,集群必须要设置为true才能配合ribbon使用负载均衡 service-url: #注册中心地址 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版 instance: instance-id: payment8001 #服务显示名称 prefer-ip-address: true #是否显示ip lease-renewal-interval-in-seconds: 20 #服务项注册中心发送心跳的默认间隔时间,单位为秒(默认是30秒) lease-expiration-duration-in-seconds: 80 #注册中心最后一次收到心跳,等待的最长时间,单位是秒,默认90秒
2.4启动类加上注解@EnableEurekaClient
package com.atguigu.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 //标识自己是Eureka客户端(也就是一个服务) - 适用于Eureka @EnableDiscoveryClient //标识自己是客户端,让注册中心发现自己是服务 - 和@EnableEurekaClient作用差不多,不过它不仅仅适用于Eureka public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
3.创建服务模块-cloud-provider-payment8002
3.1创建modul
3.2pom文件
<?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>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8001</artifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<!--热部署-代码改变自动编译-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- eureka客户端服务 可以作为服务注册到注册中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!--热部署-->
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.3配置文件yml
server: port: 8002 spring: application: name: cloud-payment-service #将会作为注册到注册中心的服务名称 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 573875306 mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: com.atguigu.springcloud.entities eureka: client: register-with-eureka: true #表识向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息,默认为true。单节点无所谓,集群必须要设置为true才能配合ribbon使用负载均衡 service-url: #注册中心地址 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版 instance: instance-id: payment8002 #服务显示名称 prefer-ip-address: true #是否显示ip lease-renewal-interval-in-seconds: 20 #服务项注册中心发送心跳的默认间隔时间,单位为秒(默认是30秒) lease-expiration-duration-in-seconds: 80 #注册中心最后一次收到心跳,等待的最长时间,单位是秒,默认90秒
3.4启动类加上注解@EnableEurekaClient
package com.atguigu.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 //标识自己是Eureka客户端(也就是一个服务) - 适用于Eureka
@EnableDiscoveryClient //标识自己是客户端,让注册中心发现自己是服务 - 和@EnableEurekaClient作用差不多,不过它不仅仅适用于Eureka
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
4.和上面一样,创建服务模块-cloud-consumer-order80
4.1创建modul
4.2pom文件
<?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>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8002</artifactId> <dependencies> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <!--热部署-代码改变自动编译--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- eureka客户端服务 可以作为服务注册到注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <!--热部署--> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> </project>
4.3.yml配置文件
server: port: 8002 spring: application: name: cloud-payment-service #将会作为注册到注册中心的服务名称 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 573875306 mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: com.atguigu.springcloud.entities eureka: client: register-with-eureka: true #表识向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息,默认为true。单节点无所谓,集群必须要设置为true才能配合ribbon使用负载均衡 service-url: #注册中心地址 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版 instance: instance-id: payment8002 prefer-ip-address: true
4.4启动类加上注解@EnableEurekaClient
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient //标识自己是Eureka客户端(也就是一个服务) public class PaymentMain8002 { public static void main(String[] args) { SpringApplication.run(PaymentMain8002.class,args); } }
5.创建服务端-cloud-eureka-server7001
5.1创建model
5.2pom文件
<?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>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-eureka-server7001</artifactId> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <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> </project>
5.3yml配置文件
server: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名字 client: register-with-eureka: false #表识不向注册中心注册自己 fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7002.com:7002/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址 server: enable-self-preservation: false #是否开启自我保护机制,默认是true eviction-interval-timer-in-ms: 2000 #最长的心跳等待时间,单位毫秒,默认9000
5.4启动类加上注解@EnableEurekaServer
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }
6.创建服务-cloud-eureka-server7002
6.1创建modul
6.2pom文件
<?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>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8002</artifactId> <dependencies> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <!--热部署-代码改变自动编译--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- eureka客户端服务 可以作为服务注册到注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <!--热部署--> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> </project>
6.3yml文件
server: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服务端的实例名字 client: register-with-eureka: false #表识不向注册中心注册自己 fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 service-url: defaultZone: http://eureka7001.com:7001/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
6.4启动类加上注解@EnableEurekaServer
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaMain7002 { public static void main(String[] args) { SpringApplication.run(EurekaMain7002.class,args); } }
7.构建cloud-api-commons
7.1创建modul
7.2pom
<?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>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-api-commons</artifactId> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <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> <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.1.0</version> </dependency> </dependencies> </project>
8.热部署
8.1添加依赖到需要热部署的模块(已添加)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
8.2添加插件到需要热部署的模块(已添加)
下一段配置黏贴到父工程当中的pom里 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build>
8.3配置Enabling automatic build
8.4update the valueof
8.5重启idea
9.表(一个简单的表-代表订单)
CREATE TABLE `payment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `serial` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
10.cloud-api-commons业务类
这里就一个实体类,一个返回结果类
package com.atguigu.springcloud.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T>{ private Integer code; private String message; private T data; public CommonResult(Integer code, String message){ this(code,message,null); } }
package com.atguigu.springcloud.entities; 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; }
11.cloud-provider-payment8001和8002业务类
8001和8002是一样的,提供同样的服务。业务代码一样。
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import com.atguigu.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 @Slf4j public class PaymentController { @Resource private PaymentService paymentService; @Value("${server.port}") private String serverport; @PostMapping(value = "/payment/create") public CommonResult create(@RequestBody Payment payment){ int result = paymentService.create(payment); log.info("*****插入结果:"+result); if (result>0){ //成功 return new CommonResult(200,"插入数据库成功" + serverport,result); }else { return new CommonResult(444,"插入数据库失败",null); } } @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id){ Payment payment = paymentService.getPaymentById(id); log.info("*****查询结果:"+payment); if (payment!=null){ //说明有数据,能查询成功 return new CommonResult(200,"查询成功" + serverport,payment); }else { return new CommonResult(444,"没有对应记录,查询ID:"+id,null); } } @Resource private 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 this.discoveryClient; } }
package com.atguigu.springcloud.dao; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.entities.PaymentExample; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @Mapper //使用了@mapper 标记这是一个映射接口 public interface PaymentMapper { int countByExample(PaymentExample example); int deleteByExample(PaymentExample example); int deleteByPrimaryKey(Long id); int insert(Payment record); int insertSelective(Payment record); List<Payment> selectByExample(PaymentExample example); Payment selectByPrimaryKey(Long id); int updateByExampleSelective(@Param("record") Payment record, @Param("example") PaymentExample example); int updateByExample(@Param("record") Payment record, @Param("example") PaymentExample example); int updateByPrimaryKeySelective(Payment record); int updateByPrimaryKey(Payment record); }
package com.atguigu.springcloud.entities; import java.util.ArrayList; import java.util.List; public class PaymentExample { protected String orderByClause; protected boolean distinct; protected List<Criteria> oredCriteria; public PaymentExample() { oredCriteria = new ArrayList<Criteria>(); } public void setOrderByClause(String orderByClause) { this.orderByClause = orderByClause; } public String getOrderByClause() { return orderByClause; } public void setDistinct(boolean distinct) { this.distinct = distinct; } public boolean isDistinct() { return distinct; } public List<Criteria> getOredCriteria() { return oredCriteria; } public void or(Criteria criteria) { oredCriteria.add(criteria); } public Criteria or() { Criteria criteria = createCriteriaInternal(); oredCriteria.add(criteria); return criteria; } public Criteria createCriteria() { Criteria criteria = createCriteriaInternal(); if (oredCriteria.size() == 0) { oredCriteria.add(criteria); } return criteria; } protected Criteria createCriteriaInternal() { Criteria criteria = new Criteria(); return criteria; } public void clear() { oredCriteria.clear(); orderByClause = null; distinct = false; } protected abstract static class GeneratedCriteria { protected List<Criterion> criteria; protected GeneratedCriteria() { super(); criteria = new ArrayList<Criterion>(); } public boolean isValid() { return criteria.size() > 0; } public List<Criterion> getAllCriteria() { return criteria; } public List<Criterion> getCriteria() { return criteria; } protected void addCriterion(String condition) { if (condition == null) { throw new RuntimeException("Value for condition cannot be null"); } criteria.add(new Criterion(condition)); } protected void addCriterion(String condition, Object value, String property) { if (value == null) { throw new RuntimeException("Value for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value)); } protected void addCriterion(String condition, Object value1, Object value2, String property) { if (value1 == null || value2 == null) { throw new RuntimeException("Between values for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value1, value2)); } public Criteria andIdIsNull() { addCriterion("id is null"); return (Criteria) this; } public Criteria andIdIsNotNull() { addCriterion("id is not null"); return (Criteria) this; } public Criteria andIdEqualTo(Long value) { addCriterion("id =", value, "id"); return (Criteria) this; } public Criteria andIdNotEqualTo(Long value) { addCriterion("id <>", value, "id"); return (Criteria) this; } public Criteria andIdGreaterThan(Long value) { addCriterion("id >", value, "id"); return (Criteria) this; } public Criteria andIdGreaterThanOrEqualTo(Long value) { addCriterion("id >=", value, "id"); return (Criteria) this; } public Criteria andIdLessThan(Long value) { addCriterion("id <", value, "id"); return (Criteria) this; } public Criteria andIdLessThanOrEqualTo(Long value) { addCriterion("id <=", value, "id"); return (Criteria) this; } public Criteria andIdIn(List<Long> values) { addCriterion("id in", values, "id"); return (Criteria) this; } public Criteria andIdNotIn(List<Long> values) { addCriterion("id not in", values, "id"); return (Criteria) this; } public Criteria andIdBetween(Long value1, Long value2) { addCriterion("id between", value1, value2, "id"); return (Criteria) this; } public Criteria andIdNotBetween(Long value1, Long value2) { addCriterion("id not between", value1, value2, "id"); return (Criteria) this; } public Criteria andSerialIsNull() { addCriterion("serial is null"); return (Criteria) this; } public Criteria andSerialIsNotNull() { addCriterion("serial is not null"); return (Criteria) this; } public Criteria andSerialEqualTo(String value) { addCriterion("serial =", value, "serial"); return (Criteria) this; } public Criteria andSerialNotEqualTo(String value) { addCriterion("serial <>", value, "serial"); return (Criteria) this; } public Criteria andSerialGreaterThan(String value) { addCriterion("serial >", value, "serial"); return (Criteria) this; } public Criteria andSerialGreaterThanOrEqualTo(String value) { addCriterion("serial >=", value, "serial"); return (Criteria) this; } public Criteria andSerialLessThan(String value) { addCriterion("serial <", value, "serial"); return (Criteria) this; } public Criteria andSerialLessThanOrEqualTo(String value) { addCriterion("serial <=", value, "serial"); return (Criteria) this; } public Criteria andSerialLike(String value) { addCriterion("serial like", value, "serial"); return (Criteria) this; } public Criteria andSerialNotLike(String value) { addCriterion("serial not like", value, "serial"); return (Criteria) this; } public Criteria andSerialIn(List<String> values) { addCriterion("serial in", values, "serial"); return (Criteria) this; } public Criteria andSerialNotIn(List<String> values) { addCriterion("serial not in", values, "serial"); return (Criteria) this; } public Criteria andSerialBetween(String value1, String value2) { addCriterion("serial between", value1, value2, "serial"); return (Criteria) this; } public Criteria andSerialNotBetween(String value1, String value2) { addCriterion("serial not between", value1, value2, "serial"); return (Criteria) this; } } public static class Criteria extends GeneratedCriteria { protected Criteria() { super(); } } public static class Criterion { private String condition; private Object value; private Object secondValue; private boolean noValue; private boolean singleValue; private boolean betweenValue; private boolean listValue; private String typeHandler; public String getCondition() { return condition; } public Object getValue() { return value; } public Object getSecondValue() { return secondValue; } public boolean isNoValue() { return noValue; } public boolean isSingleValue() { return singleValue; } public boolean isBetweenValue() { return betweenValue; } public boolean isListValue() { return listValue; } public String getTypeHandler() { return typeHandler; } protected Criterion(String condition) { super(); this.condition = condition; this.typeHandler = null; this.noValue = true; } protected Criterion(String condition, Object value, String typeHandler) { super(); this.condition = condition; this.value = value; this.typeHandler = typeHandler; if (value instanceof List<?>) { this.listValue = true; } else { this.singleValue = true; } } protected Criterion(String condition, Object value) { this(condition, value, null); } protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { super(); this.condition = condition; this.value = value; this.secondValue = secondValue; this.typeHandler = typeHandler; this.betweenValue = true; } protected Criterion(String condition, Object value, Object secondValue) { this(condition, value, secondValue, null); } } }
package com.atguigu.springcloud.service; import com.atguigu.springcloud.entities.Payment; import org.apache.ibatis.annotations.Param; public interface PaymentService { public int create(Payment payment); //写 public Payment getPaymentById(@Param("id") Long id); //读取 }
package com.atguigu.springcloud.service.impl; import com.atguigu.springcloud.dao.PaymentMapper; import com.atguigu.springcloud.entities.Payment; import com.atguigu.springcloud.service.PaymentService; import org.apache.ibatis.annotations.Param; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; @Service @Transactional public class PaymentServiceImpl implements PaymentService { @Resource private PaymentMapper paymentDao; public int create(Payment payment){ return paymentDao.insert(payment); } public Payment getPaymentById( Long id){ return paymentDao.selectByPrimaryKey(id); } }
12.cloud-consumer-order80业务
package com.atguigu.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 { //创建RestTemplate的bean @Bean @LoadBalanced //设置负载均衡 让它可以同为微服务名称调用服务 - 默认调用同名服务集群是才去轮询调用 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
@LoadBalanced
使RestTemplate的实例调用服务名称相同的8001/8002服务,实现负载均衡。默认调用方式是集群
package com.atguigu.springcloud.controller; import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @RestController @Slf4j public class OrderController { public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";//服务名称-在8001/8002的yml文件中配置 //现在一个服务也是集群的,有多个地址, // 所以就是用服务名称而不是地址-这个地址下面有多个服务 @Resource private RestTemplate restTemplate; //简单的访问restful服务的模板类,用于访问Restful @PostMapping("/consumer/payment/create") public CommonResult<Payment> create(@RequestBody Payment payment){ return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);//通过服务名称去调用8001/8002的服务接口 } @GetMapping("/consumer/payment/get/{id}") public CommonResult<Payment> getPayment(@PathVariable("id") Long id){ return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class); } }
@Resource
注入对象,和@Autowired类似
13启动
启动顺序,先启动注册中心7001,7002,再启动服务提供者8001,8002,最后启动消费者80
访问 http://localhost:7001/
DS Replicas下面是集群中的另外一个,7002注册中心
Application是向注册中心注册的服务8001,8002
14.8001、8002yml中几个配置说明
instance-id: payment8001 #服务显示名称
这里配置的就是右侧的这个名称
prefer-ip-address: true #是否显示ip
鼠标移到右侧这里的时候,左下角显示这个服务ip
15.Eureka自我保护
默认情况下,自我保护是开启的。如果需要关闭,需要到注册中心的yml中配置enable-self-preservation: false。我已经在7001加入了这个配置,所以现在看到的是如下提示
一般生产环境都会开启自我保护而不是关闭
16.Eureka Client通知Eureka Server
在Spring Cloud中,可以通过HTTP请求的方式,通知Eureka Client优雅停服,这个请求一旦发送到Eureka Client,那么Eureka Client会发送一个shutdown请求到Eureka Server,Eureka Server接收到这个shutdown请求后,会在服务列表中标记这个服务的状态为down,同时Eureka Client应用自动关闭。这个过程就是优雅停服。
如果使用了优雅停服,则不需要再关闭Eureka Server的服务保护模式。
1、POM
优雅停服是通过Eureka Client发起的,所以需要在Eureka Client中增加新的依赖,这个依赖是autuator组件,添加下述依赖即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> </dependency>
2、修改全局配置文件:
Eureka Client默认不开启优雅停服功能,需要在全局配置文件中新增如下内容:
# 启用shutdown,优雅停服功能 endpoints.shutdown.enabled=true # 禁用密码验证 endpoints.shutdown.sensitive=false
3、发起shutdown请求:
必须通过POST请求向Eureka Client发起一个shutdown请求。请求路径为:http://ip:port/shutdown。可以通过任意技术实现,如:HTTPClient、form表单,AJAX等。
17.Eureka Server的安全认证
Eureka Server作为Spring Cloud中的服务注册中心,如果可以任意访问的话,那么其安全性太低。所以Spring Cloud中也有为Eureka Server提供安全认证的方式。可以使用spring-boot-starter-security组件来为Eureka Server增加安全认证。
1、配置注册中心的Maven的pom文件
<!-- spring boot security安全认证启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
2、配置注册中心的application.yml
# 开启基于http basic的安全认证 security.basic.enabled=true # 设置安全认证用户名 security.user.name=root # 设置安全认证密码 security.user.password=123456
3.注册中心关闭Spring Security的CSRF验证
package com.wind.eurekaserver; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** 1. 如果eurekaServer设置了登录密码 就必须关闭Spring Security的CSRF验证 */ @EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); //关闭csrf super.configure(http); } }
4.配置Client的application.yml
defaultZone加入账号密码
defaultZone: http://root:123456@eureka7001.com:7001/eureka,http://root:123456@eureka7002.com:7002/eureka #集群版
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?