Spring Cloud 是一个基于 Spring Boot 实现的微服务架构开发工具集。以下是一些在 Spring Boot 2 之后常用的 Spring Cloud 组件:

一、服务发现——Eureka 或 Consul

  1. Eureka
    • 作用:实现服务注册与发现。服务提供者将自己的信息注册到 Eureka Server,服务消费者从 Eureka Server 获取服务提供者的地址列表,从而实现服务的调用。
    • 特点:具备自我保护机制,当网络分区等故障导致部分服务实例不能正常通信时,Eureka Server 不会立即将这些实例从注册表中剔除,以防止误剔除正常服务。
      2、代码
      以下是使用 Spring Boot 2 实现 Eureka 服务注册与发现的示例代码:

2.1. 创建服务提供者项目

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

application.yml 文件

server:
  port: 8081

spring:
  application:
    name: service-provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ServiceProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceProviderApplication.class, args);
    }
}

一个简单的服务接口

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from service provider!";
    }
}

2.2. 创建 Eureka 服务注册中心项目

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

application.yml 文件

server:
  port: 8761

spring:
  application:
    name: eureka-server

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

首先启动 Eureka 服务注册中心项目,然后启动服务提供者项目。服务提供者会将自己的信息注册到 Eureka 服务注册中心,其他服务可以从 Eureka 服务注册中心获取服务提供者的地址信息,从而实现服务的发现和调用。

  1. Consul
    • 作用:也是用于服务发现和配置管理。它提供了强大的服务健康检查机制,可以实时监测服务的状态。
    • 特点:支持多数据中心,具有高可用和分布式的特性。可以通过 HTTP API 和 DNS 接口进行服务发现。

二、负载均衡——Ribbon

  • 作用:在客户端实现负载均衡。当服务消费者调用服务提供者时,Ribbon 会从服务提供者列表中选择一个实例进行调用,以实现负载均衡的效果。
  • 特点:可以与多种服务发现组件集成,如 Eureka、Consul 等。支持多种负载均衡策略,如轮询、随机、加权轮询等,可以根据实际需求进行配置。

代码

以下是使用 Spring Boot 2 结合 Ribbon 实现负载均衡的示例代码:

1. 创建服务提供者项目(与 Eureka 示例中的服务提供者类似,这里假设服务名为service-provider,端口分别为 8081 和 8082)

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

application.yml 文件(端口为 8081 的服务提供者)

server:
  port: 8081

spring:
  application:
    name: service-provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

application.yml 文件(端口为 8082 的服务提供者)

server:
  port: 8082

spring:
  application:
    name: service-provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类和服务接口与 Eureka 示例中的服务提供者相同

2. 创建服务消费者项目

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
</dependencies>

application.yml 文件

server:
  port: 8080

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ServiceConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

服务调用类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/callService")
    public String callServiceProvider() {
        return restTemplate.getForObject("http://service-provider/hello", String.class);
    }
}

在这个示例中,服务消费者通过RestTemplate调用服务提供者的接口,由于添加了@LoadBalanced注解,RestTemplate会结合 Ribbon 实现负载均衡,自动从注册到 Eureka 的多个服务提供者实例中选择一个进行调用。

三、断路器——Hystrix

  • 作用:防止单个服务的故障级联影响到整个系统。当某个服务出现故障时,Hystrix 会快速熔断该服务的调用,避免大量请求堆积导致系统崩溃。
  • 特点:提供了降级机制,当服务不可用时,可以返回预设的降级结果。同时,Hystrix 还可以统计服务调用的延迟、失败率等指标,以便进行监控和优化。

以下是使用 Spring Boot 2 实现 Hystrix 熔断功能的示例代码:

一、创建服务提供者项目(与之前的示例类似)

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

application.yml 文件

server:
  port: 8081

spring:
  application:
    name: service-provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类和服务接口与之前的示例相同

二、创建服务消费者项目

pom.xml 文件

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
</dependencies>

application.yml 文件

server:
  port: 8080

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}

服务调用类

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "fallbackMethod")
    @GetMapping("/callService")
    public String callServiceProvider() {
        return restTemplate.getForObject("http://service-provider/hello", String.class);
    }

    public String fallbackMethod() {
        return "Service is temporarily unavailable.";
    }
}

在这个示例中,服务消费者通过RestTemplate调用服务提供者的接口。当服务提供者不可用时,@HystrixCommand注解会触发熔断机制,调用指定的回退方法fallbackMethod,返回预设的错误信息。

四、网关——Spring Cloud Gateway

  • 作用:作为系统的统一入口,负责请求的路由、过滤、限流等功能。
  • 特点:基于 Spring WebFlux 实现,具有非阻塞、高性能的特点。可以通过配置文件或代码定义路由规则,支持多种过滤器,如请求头过滤、参数过滤、IP 过滤等。

五、配置中心——Spring Cloud Config

  • 作用:集中管理系统的配置信息。可以将配置文件存储在 Git 仓库、本地文件系统等地方,服务启动时从配置中心获取配置信息。
  • 特点:支持动态刷新配置,当配置信息发生变化时,可以通过消息总线(如 Spring Cloud Bus)通知服务实例进行配置更新,无需重启服务。

六、服务调用——Feign

  • 作用:简化服务调用的代码编写。通过定义接口并添加注解的方式,Feign 可以自动生成服务调用的客户端代码,使得服务调用像调用本地方法一样简单。
  • 特点:可以与 Ribbon 和 Hystrix 集成,实现负载均衡和断路器功能。支持多种 HTTP 客户端,如 OkHttp、HttpClient 等。
    以下是修改后的使用 Spring Boot 2 结合 Feign 实现负载均衡和使用@FeignClient的熔断通过Callback注解的示例代码:

代码

  1. pom.xml 文件
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign.okhttp</groupId>
        <artifactId>feign-okhttp</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign.httpclient</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
</dependencies>
  1. application.yml 文件
server:
  port: 8080

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  1. 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class ServiceConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}
  1. 定义 Feign 客户端接口

    • 使用OkHttp
import feign.Client;
import feign.okhttp.OkHttpClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "service-provider", url = "http://localhost:8081", configuration = OkHttpConfiguration.class)
public interface ServiceProviderClient {

    @GetMapping("/hello")
    @HystrixCommand(fallbackMethod = "fallbackHello")
    String hello();

    default String fallbackHello() {
        return "Service is temporarily unavailable.";
    }
}

class OkHttpConfiguration {
    public Client feignClient() {
        return new OkHttpClient();
    }
}
  • 使用HttpClient
import feign.Client;
import feign.httpclient.ApacheHttpClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "service-provider", url = "http://localhost:8081", configuration = HttpClientConfiguration.class)
public interface ServiceProviderClient {

    @GetMapping("/hello")
    @HystrixCommand(fallbackMethod = "fallbackHello")
    String hello();

    default String fallbackHello() {
        return "Service is temporarily unavailable.";
    }
}

class HttpClientConfiguration {
    public Client feignClient() {
        return new ApacheHttpClient();
    }
}
  1. 服务调用类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConsumerController {

    @Autowired
    private ServiceProviderClient serviceProviderClient;

    @GetMapping("/callService")
    public String callServiceProvider() {
        return serviceProviderClient.hello();
    }
}

使用 Ribbon 实现负载均衡

Feign 默认集成了 Ribbon,当你使用@FeignClient注解指定服务名时,Feign 会在后台使用 Ribbon 从服务注册中心(如 Eureka)获取服务提供者的实例列表,并进行负载均衡调用。无需额外的代码配置,只要确保以下几点:

  1. 服务消费者项目添加了spring-cloud-starter-openfeignspring-cloud-starter-netflix-eureka-client依赖。
  2. 服务消费者项目的application.yml文件中正确配置了 Eureka 服务注册中心的地址。
  3. 服务提供者项目将自己注册到 Eureka 服务注册中心。

这样,当服务消费者通过 Feign 调用服务提供者的接口时,Ribbon 会自动实现负载均衡。

10-17 21:20