面对环视的强敌,我一直问自己这样一个问题:现在开始还来得及吗?面对残酷的现实世界,我也不断寻找让自己躺平的理由,可没有一个理由可以让我坦然接受现在的一切。于是,我决定强攻!可这满头乱发,该如何抓呢?好不容易揪住一根银丝,却不知道应该如何开始!只能日日唉声叹气,毫无进展!可一切总要有个说法,徒自烦闷终是于事无补。因此我决定暂时放弃微服务理论部分的知识,直接学习微服务框架Spring Cloud的用法,同时研究其源码。
学习一个东西,我们首先要弄清楚三个问题:是什么,干什么,怎么用。下面先来看一下通义千问大模型关于Spring Cloud的描述:
Spring Cloud是一个由Pivotal团队提供的基于Java的微服务工具集,它为开发者设计并实现微服务架构提供了全面的解决方案。Spring Cloud构建在Spring Boot之上,其核心目标是简化分布式系统和服务的开发流程,通过一系列的开源组件和工具,为开发者提供了服务发现注册、配置管理、熔断器、智能路由、微代理、控制总线、一次性令牌、全局锁、主节点选举、分布式会话、集群状态管理等分布式系统中常见的功能模块。
简而言之,Spring Cloud是一个针对微服务架构设计的标准化一站式开发框架,它通过整合和封装各种成熟的第三方库和服务,为开发者提供了一整套开箱即用的微服务开发工具及最佳实践,使得在搭建和管理分布式系统时能更高效、更便捷,从而更好地应对云计算环境下的服务治理挑战。
通过这段描述,我们可以得出这样一些信息:Spring Cloud是一套基于Java的微服务工具集,为开发者提供了在分布式系统(微服务架构)中快速构建、部署和管理微服务的一站式解决方案。它是在Spring Boot基础上创建的,用于简化分布式系统和服务的复杂性,促进各服务间的协同工作和统一管理。Spring Cloud整合并封装了一系列经过实战检验的成熟框架和组件,譬如:
通过第一小节,我们了解了Spring Cloud的定义,同时也知道了Spring Cloud可以用来做些什么?可是对于这个工具如何使用,我们却鲜有提及。这一小节我们就来重点聊聊Spring Cloud的用法。然而,因为Spring Cloud是一套微服务工具集,其涉及的框架和组件非常多,譬如:服务注册与发现、负载均衡与服务调用、网关服务、配置中心、断路器、服务跟踪等等,所以想在一小节中就把Spring Cloud的用法完全弄懂是不太现实的。这就好比想一口吃成胖子,实属一厢情愿。但是,我们也不能因此放弃对这个框架用法的讨论!因此本小节我们将从一个小点(Spring Cloud中的注册中心组件)开始,通过对这个小点的分析(学习这个组件的基本用法),然后逐步攻克Spring Cloud这座高大的城池(学会Spring Cloud的用法)。在开始前,我们要先了解一下注册中心这个概念。
注册中心,在分布式系统特别是微服务架构中,是一种服务注册与发现的关键组件。它本质上是一个服务注册表(service registry),用于存储和管理各个服务实例的服务元数据和网络位置信息(如IP地址、端口号),确保服务间的相互调用能够准确高效地找到对方。具体来说,注册中心的作用有:
在实际应用中,常见的注册中心产品和技术有:
无论如何,通过注册中心,微服务架构得以灵活扩展和动态调整,实现了服务间松耦合和高可用性。下面就来看看如何利用Spring Cloud中的Eureka组件来实现一个注册中心吧!
首先创建一个Maven项目,取名为eureka-server。然后在项目中的pom.xml文件中配置Eureka依赖信息,该文件的详细信息如下所示:
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.com.chinasoft</groupId>
<artifactId>springcloud-eureka-server</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springcloud-eureka-server</name>
<!--<url>http://maven.apache.org</url>-->
<!--引入springboot-parent父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--引入 springcloud 的 euekea server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--指定下载源和使用springcloud的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
注意:上述代码中的spring-cloud-starter-netflix-eureka-server,就是我们要引入项目中的eureka依赖。
接着编写启动类。该启动的名字为EurekaServerApplication。其源码详细如下所示(注意这个类上的注解@EnableEurekaServer,它表示开启Eureka Server):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
*
*/
@SpringBootApplication
@EnableEurekaServer // 当前使用eureka的server
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
最后编写项目配置文件,即application.yml。在该配置文件中添加相关配置项,譬如:项目名称(spring.application.name)、端口(server.port)等。配置文件详细信息如下所示:
server:
port: 8700 # 端口自己决定
# 指定当前eureka客户端的注册地址,也就是eureka服务的提供方,当前配置的服务的注册服务方
eureka:
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
register-with-eureka: false #自身 不在向eureka注册
fetch-registry: false #启动时禁用client的注册
instance:
hostname: localhost
#指定应用名称
spring:
application:
name: eureka-server
接着创建一个Maven项目,取名为eureka-client。然后在项目中的pom.xml文件中配置相关依赖信息,该文件的详细信息如下所示:
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.com.chinasoft</groupId>
<artifactId>springcloud-eureka-client</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springcloud-eureka-client</name>
<!--<url>http://maven.apache.org</url>-->
<!--引入springboot-parent父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--引入 springcloud 的 euekea server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--指定下载源和使用springcloud的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
注意:上述代码中的spring-cloud-starter-netflix-eureka-client,就是我们要引入项目中的eureka依赖。
接着编写启动类。该启动的名字为EurekaServiceApplication。其源码详细如下所示(注意这个类上的注解@EnableDiscoveryClient,它表示当前服务是一个Eureka的客户端):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
*
*/
@SpringBootApplication
@EnableDiscoveryClient // 代表自己是一个服务提供方
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
再次编写Controller类,其中控制器用于接收客户端请求。这个Controller类的详细代码如下所示:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/Hello")
public class Controller {
@RequestMapping("/World")
public String helloWorld(String s) {
System.out.println("传入的值为:" + s);
return "传入的值为:" + s;
}
}
最后编写项目配置文件,即application.yml。在该配置文件中添加相关配置项,譬如:项目名称(spring.application.name)、端口(server.port)等。配置文件详细信息如下所示:
server:
port: 8701 # 服务提供方
# 指定当前eureka客户端的注册地址,
eureka:
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:8700/eureka
instance:
hostname: localhost
#当前服务名称
spring:
application:
name: eureka-service
接着创建一个Maven项目,取名为eureka-consumer。然后在项目中的pom.xml文件中配置相关依赖信息,该文件的详细信息如下所示:
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.com.chinasoft</groupId>
<artifactId>eureka-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springcloud-ribbon</name>
<!--<url>http://maven.apache.org</url>-->
<!--引入springboot-parent父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--引入 springcloud 的 euekea server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--引入 springcloud 的 ribbon 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!--指定下载源和使用springcloud的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
注意:上述代码中的spring-cloud-starter-netflix-eureka-client和spring-cloud-starter-ribbon,就是我们要引入到项目中的依赖。
接着编写启动类。该启动的名字为EurekaConsumerApplication。其源码详细如下所示(注意这个类上的注解@EnableDiscoveryClient,它表示当前服务是一个Eureka的客户端):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 当前使用eureka的server
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
再次编写Controller和配置类,其中控制器用于接收客户端请求,配置类用于向容器中注入关键对象,其详细代码如下所示:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/Hello")
public class ConsumerController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/Consumer")
public String helloWorld(String s) {
System.out.println("传入的值为:" + s);
//第一种调用方式
//String forObject = new RestTemplate().getForObject("http://localhost:8071/Hello/World?s=" + s, String.class);
//第二种调用方式
//根据服务名 获取服务列表 根据算法选取某个服务 并访问某个服务的网络位置。
// ServiceInstance serviceInstance = loadBalancerClient.choose("EUREKA-SERVICE");
// String forObject = new RestTemplate().getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/Hello/World?s="+s,String.class);
//第三种调用方式 需要restTemplate注入的方式
String forObject = restTemplate.getForObject("http://EUREKA-SERVICE/Hello/World?s=" + s, String.class);
return forObject;
}
}
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 Beans {
//管理简单对象
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
最后编写项目配置文件,即application.yml。在该配置文件中添加相关配置项,譬如:项目名称(spring.application.name)、端口(server.port)等。配置文件详细信息如下所示:
server:
port: 8702 # 服务消费方
# 指定当前eureka客户端的注册地址,
eureka:
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:8700/eureka
instance:
hostname: localhost
#当前服务名称
spring:
application:
name: eureka-consumer
通过这篇文章,我对Spring Cloud有了初步的了解:Spring Cloud是一个基于Java的微服务工具集,它为开发者设计并实现微服务架构提供了全面的解决方案。因此个人理解Spring Cloud就是一个方便开发者开发分布式项目的工具集。其整合并封装了一系列经过实战检验的成熟框架和组件,譬如:服务注册与发现、负载均衡与服务调用、网关服务、配置中心、断路器、服务跟踪等等,同时Spring Cloud还对消息队列、控制总线和分布式事务提供了支持。总而言之,通过Spring Cloud工程师可以很容易的设计和开发出一套具有可靠性能的分布式应用。
又是通过这篇文章,我对注册中心这个概念有了基本了解:注册中心,在分布式系统尤其是微服务架构中,是一种服务注册与发现的关键组件。其本质上是一个服务注册表(service registry),用于存储和管理各个服务实例的网络位置信息(如IP地址、端口号)和服务元数据,确保服务间的相互调用能够准确高效地找到对方。总体来看,注册中心就是一个类似于操作系统的注册表,通过这个注册表我们能够很容易的找到自己想用的服务。
最后还是通过这篇文章,我对Spring Cloud这个工具集中的Eureka组件的用法有了一定的了解:知道了如何编写Eureka服务方(即注册中心)、如何编写Eureka服务(即服务提供者)、如何编写Eureka消费者。但是这些信息是如何被Eureka管理的呢?服务提供者是如何注册到Eureka服务端(注册中心的)?服务提供者和Eureka服务端之间是通过什么形式的连接通讯的?Eureka服务端是如何知道服务提供者的状态的(上线、下线)?Eureka消费者是如何从Eureka服务端拉取存活的服务的?Eureka消费者是如何调用Eureka服务提供者的?等等,这些问题都需要我们通过后续的文章一步步深入梳理。