Spring Cloud

Spring Cloud

微服务概述

微服务可以在“自己的程序”中运行,并通过“轻量级设备与 HTTP 型 API 进行沟通”。关键在于该服务可以在自己的程序中运行。通过这一点我们就可以将服务公开与微服务架构(在现有系统中分布一个 API)区分开来。在服务公开中,许多服务都可以被内部独立进程所限制。如果其中任何一个服务需要增加某种功能,那么就必须缩小进程范围。在微服务架构中,只需要在特定的某种服务中增加所需功能,而不影响整体进程。

微服务的核心是 API,在一个大型系统中,我们可以将其拆分为一个个的子模块,每一个模块就可以是一个服务,各服务之间通过 API 进行通信。

什么是 Spring Cloud

Spring Cloud是微服务架构思想的一个具体实现,它为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理、服务发、断路器,智能路由、微代理、控制总线等)。

Spring Cloud 基于 Spring Boot 框架,它不重复造轮子,而是将第三方实现的微服务应用的一些模块集成进去。准确的说,Spring Cloud 是一个容器。

1、Eureka服务注册与发现

服务发现是基于微服务的体系结构的主要宗旨之一。尝试手动配置每个客户端或某种形式的约定可能很困难并且很脆弱。Eureka是Netflix Service Discovery服务器和客户端。可以将服务器配置和部署为高可用性,每个服务器将有关已注册服务的状态复制到其他服务器。

服务注册中心

首先,创建一个 Maven 主工程,主工程的 pom.xml 添加如下内容:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
                <exclusions>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>

接着,在主工程基础上创建两个 module:一个 module 为服务注册中心,一个 module 为服务提供者(即客户端)。

下面将详细演示如何创建服务注册中心。

1.右键工程 -> New -> Module,如下图所示:

这里写图片描述

2.选择 next,输入 moudle 名,如下图所示:

这里写图片描述

这里写图片描述

3.点击 next -> finish,如下图所示:

这里写图片描述

4.然后在 pom.xml 添加依赖:

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

创建启动类 Application.java:

@SpringBootApplication
@EnableEurekaServer
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这里,我们注意到除了前面提到的 @SpringBootApplication外,这个类还增加了一个注解:EnableEurekaServer,这个注解的作用就是标注该应用程序是一个注册中心,只是添加这个注解还不够,还需要增加配置。

在 resources 下面创建 application.yml 并添加如下内容:

server:
  port: 8761
eureka:
  server:
    enable-self-preservation: false #是否开启自我保护,默认为 true,在开启自我保护的情况下,注册中心在丢失客户端时,会进入自动保护模式,注册中心并不会将该服务从注册中心删除掉。这里我设置为 false,即关闭自我保护。根据我的经验,如果设置为 true,在负载均衡条件下,一个服务挂掉后,注册中心并没有删掉该服务,会导致客户端请求的时候可能会请求到该服务,导致系统无法访问,所以我推荐将这个属性设置为 false。
  instance:
    preferIpAddress: true #是否以 IP 注册到注册中心,Eureka 默认是以 hostname 来注册的。
    hostname: ${spring.cloud.client.ipAddress}
    instanceId: ${spring.cloud.client.ipAddress}:${server.port}
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/  #注册中心默认地址。

启动该应用程序,打开浏览器并访问:http://localhost:8761。如果看到如下界面,说明注册中心已经启动起来了:

这里写图片描述

服务提供者

我们有了注册中心,那么就可以创建一个服务提供者(即客户端)注册到注册中心去了。

同样地,按照注册中心的创建方式,创建一个 module,并且在 pom.xml 添加如下内容:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>

然后创建 Application.java:

@SpringBootApplication
@EnableEurekaClient
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这里用到了一个注解:EnableEurekaClient,标注了此注解,说明该项目是一个服务提供者。

然后创建配置文件 application.yml:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ #指定注册中心的地址。
server:
  port: 8762
spring:
  application:
    name: eurekaclient  #为该服务的名字

启动该工程,重新访问:http://localhost:8761,即可看到如下界面:

这里写图片描述

我们可以看到,刚刚创建的服务提供者 eurekaclient 已经被注册到注册中心了。

2、Gateway服务网关

在实际的项目中,一个项目可能会包含很多个服务,每个服务的端口和 IP 都可能不一样。那么,如果我们以这种形式提供接口给外部调用,代价是非常大的。从安全性上考虑,系统对外提供的接口应该进行合法性校验,防止非法请求,如果按照这种形式,那每个服务都要写一遍校验规则,维护起来也很麻烦。

这个时候,我们需要统一的入口,接口地址全部由该入口进入,而服务只部署在局域网内供这个统一的入口调用,这个入口就是我们通常说的服务网关。

Spring Cloud 给我们提供了这样一个解决方案,那就是 gateway,它的作用就是进行路由转发、异常处理和过滤拦截。下面,我将演示如果使用 gateway创建一个服务网关。

<!-- Spring cloud gateway 网关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>3.1.3</version>
        </dependency>

创建自定义全局网关类MyGlobalFilter

/**
 * 自定义全局网关过滤器(GlobalFilter)
 */
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered   {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("进入自定义的全局过滤器 MyGlobalFilter" + new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null) {
            log.info("参数 uname 不能为 null!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //过滤器的顺序,0 表示第一个
        return 0;
    }
}

最后添加 application.yml 配置文件,内容如下:

server:
  port: 9527 #端口号

spring:
  application:
    name: microServiceCloudGateway  #服务注册中心注册的服务名

  cloud:
    gateway: #网关路由配置
      discovery:
        locator:
          enabled: true #默认值为 true,即默认开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        #将 micro-service-cloud-provider-dept-8001 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 9527
        - id: provider_dept_list_routh   #路由 id,没有固定规则,但唯一,建议与服务名对应
          uri: lb://MICROSERVICECLOUDPROVIDERDEPT #动态路由,使用服务名代替上面的具体带端口   lb:协议表示开启负载均衡
          predicates:
            #以下是断言条件,必选全部符合条件
            - Path=/findall/**    #断言,路径匹配 注意:Path 中 P 为大写
            - Method=GET #只能时 GET 请求时,才能访问
          filters:
            - PrefixPath=/user #在请求路径上增加一个前缀 /user

eureka:
  instance:
    instance-id: micro-service-cloud-gateway-9527
    hostname: micro-service-cloud-gateway
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

然后我们启动服务注册中心、服务提供者、服务网关,访问地址:http://localhost:9527/api/index,我们可以看到和之前的界面完全一样。

3、服务消费者

3.1 基于RestTemplate的服务间调用

创建一个消费者

在根项目上创建一个 module,命名为 consumer,然后在 pom.xml 添加如下内容:

<!--Spring Cloud Eureka 客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--Spring Cloud Ribbon 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

创建 application.yml,内容如下:

server:
  port: 81 #端口号

eureka:
  client:
    register-with-eureka: false #本微服务为服务消费者,不需要将自己注册到服务注册中心
    fetch-registry: true  #本微服务为服务消费者,需要到服务注册中心搜索服务
    service-url:
      defaultZone: http://localhost:9527/eureka/

在启动类上加注解@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}

创建一个配置类ConfigBean,将 RestTemplate 注入到容器中

@Configuration
public class ConfigBean {
    @Bean //将 RestTemplate 注入到容器中
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

创建一个UserController_Consumer

@RestController
@RequestMapping("/consumer/user")
public class UserController_Consumer {
    // 微服务提供者地址,//后面跟的是对应服务提供者在eureka中的名称
    private static final String REST_URL = "http://MICROSERVICECLOUDPROVIDERDEPT";
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/index")
    public String selectById(){
        return restTemplate.getForObject(REST_URL+"/index", String.class);
    }
}

分别启动注册中心 EurekaServer、服务提供者EurekaClient(这里服务提供者启动两次,端口分别为8762、8763,以观察 Feign 的负载均衡效果)。

在浏览器访问https://localhost:9527/index

浏览器窗口打印如下信息

Hello World!,端口:8762
Hello World!,端口:8763

3.2定制 Ribbon 负载均衡策略

创建一个负载均衡策略的配置类MySelfRibbonRuleConfig

/**
 * 定制 Ribbon 负载均衡策略的配置类
 * 该自定义 Ribbon 负载均衡策略配置类 不能在 net.biancheng.c 包及其子包下
 * 否则所有的 Ribbon 客户端都会采用该策略,无法达到特殊化定制的目的
 */
@Configuration
public class MySelfRibbonRuleConfig {

    @Bean
    public IRule myRule() {
        //自定义 Ribbon 负载均衡策略
        return new RoundRobinRule(); //自定义,随机选择某一个微服务,执行五次
    }
}

在配置类ConfigBean,注入ConfigBean的方法上加上@LoadBalanced

@Configuration
public class ConfigBean {
    @Bean //将 RestTemplate 注入到容器中
    @LoadBalanced //在客户端使用 RestTemplate 请求服务端时,开启负载均衡(Ribbon)
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

在启动类上加上这个注解@RibbonClient(name = "MICROSERVICECLOUDPROVIDERDEPT", configuration = MySelfRibbonRuleConfig.class)

@SpringBootApplication
@EnableEurekaClient
//自定义 Ribbon 负载均衡策略在主启动类上使用 RibbonClient 注解,在该微服务启动时,就能自动去加载我们自定义的 Ribbon 配置类,从而是配置生效
// name 为需要定制负载均衡策略的微服务名称(application name)
// configuration 为定制的负载均衡策略的配置类,
// 且官方文档中明确提出,该配置类不能在 ComponentScan 注解(SpringBootApplication 注解中包含了该注解)下的包或其子包中,即自定义负载均衡配置类不能在 net.biancheng.c 包及其子包下
@RibbonClient(name = "MICROSERVICECLOUDPROVIDERDEPT", configuration = MySelfRibbonRuleConfig.class)
public class MicroServiceCloudConsumerDept80Application {

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

}

这样我们就成功自定义了ribbon的负载均衡策略,项目中可以根据实际需要定制负载均衡策略

3.3 基于Feign的服务间调用

什么是 Feign

Feign 是一个声明式的 HTTP 客户端,它简化了 HTTP 客户端的开发。使用 Feign,只需要创建一个接口并注解,就能很轻松的调用各服务提供的 HTTP 接口。Feign 默认集成了 Ribbon,默认实现了负载均衡。

创建 Feign 服务

在根项目上创建一个 module,命名为 feign,然后在 pom.xml 添加如下内容:

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
    </dependencies>

创建 application.yml,内容如下:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9527/eureka/
server:
  port: 8081
spring:
  application:
    name: feign

最后创建一个启动类 Application:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}

我们可以看到启动类增加了一个新的注解:@EnableFeignClients,如果我们要使用 Feign 声明式 HTTP 客户端,必须要在启动类加入这个注解,以开启 Feign。

这样,我们的 Feign 就已经集成完成了,那么如何通过 Feign 去调用之前我们写的 HTTP 接口呢?请看下面的做法。

首先创建一个接口 ApiService,并且通过注解配置要调用的服务地址:

@FeignClient(value = "eurekaclient")
public interface ApiService {
 
    @RequestMapping(value = "/index",method = RequestMethod.GET)
    String index();
}

分别启动注册中心 EurekaServer、服务提供者EurekaClient(这里服务提供者启动两次,端口分别为8762、8763,以观察 Feign 的负载均衡效果)。

然后在 Feign 里面通过单元测试来查看效果。

1.添加单元测试依赖。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

2.添加测试代码。

@SpringBootTest(classes = Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class TestDB {
 
    @Autowired
    private ApiService apiService;
 
    @Test
    public void test(){
        try {
            System.out.println(apiService.index());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

最后分别启动两次单元测试类,我们可以发现控制台分别打印如下信息:

Hello World!,端口:8762
Hello World!,端口:8763

由此可见,我们成功调用了服务提供者提供的接口,并且循环调用不同的接口,说明它自带了负载均衡效果。

4、Hystrix服务异常处理

​ 我们的服务最终是部署在服务器上,因为各种原因,服务难免会发生故障,那么其他服务去调用这个服务就会调不到,甚至会一直卡在那里,导致用户体验不好。针对这个问题,我们就需要对服务接口做错误处理,一旦发现无法访问服务,则立即返回并报错,我们捕捉到这个异常就可以以可读化的字符串返回到前端。

为了解决这个问题,业界提出了熔断器模型。

Hystrix 组件

SpringCloud 集成了 Netflix 开源的 Hystrix 组件,该组件实现了熔断器模型,它使得我们很方便地实现熔断器。

在实际项目中,一个请求调用多个服务是比较常见的,如果较底层的服务发生故障将会发生连锁反应。这对于一个大型项目是灾难性的。因此,我们需要利用 Hystrix 组件,当特定的服务不可用达到一个阈值(Hystrix 默认5秒20次),将打开熔断器,即可避免发生连锁反应。

代码实现

紧接上一篇的代码,Feign 是默认自带熔断器的,在 D 版本 SpringCloud 中是默认关闭的,我们可以在 application.yml 中开启它:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9527/eureka/
server:
  port: 8081
spring:
  application:
    name: feign
#开启熔断器
feign:
  hystrix:
    enabled: true

新建一个类 ApiServiceError.java 并实现 ApiService:

@Component
public class ApiServiceError implements ApiService {
 
    @Override
    public String index() {
        return "服务发生故障!";
    }
}

然后在 ApiService 的注解中指定 fallback:

@FeignClient(value = "eurekaclient",fallback = ApiServiceError.class)
public interface ApiService {
 
    @RequestMapping(value = "/index",method = RequestMethod.GET)
    String index();
}

分别启动注册中心 EurekaServer、服务提供者 EurekaClient 和服务消费者 Feign,然后访问:http://localhost:8081/index,可以看到顺利请求到接口:

enter image description here

然后停止 EurekaClient,再次请求,可以看到熔断器生效了:

enter image description here

熔断器监控

Hystrix 给我们提供了一个强大的功能,那就是 Dashboard。Dashboard 是一个 Web 界面,它可以让我们监控 Hystrix Command 的响应时间、请求成功率等数据。

下面我们开始改造 Feign 工程,在 Feign 工程的 pom.xml 下加入依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

这三个依赖缺一不可,否则会有意想不到的事情发生。

然后在启动类 Application.java 中加入 @EnableHystrixDashboard@EnableCircuitBreaker 注解:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrixDashboard
@EnableCircuitBreaker
@RibbonClient(name = "MICROSERVICECLOUDPROVIDERDEPT", configuration = MySelfRibbonRuleConfig.class)
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}

然后分别启动 EurekaServer、EurekaClient 和 Feign 并访问:http://localhost:8081/hystrix,可以看到如下画面:

enter image description here

按照上图箭头所示,输入相关信息后,点击 Monitor Stream 按钮进入下一界面,打开新窗口访问:http://localhost:8081/index,在 Dashboard 界面即可看到 Hystrix 监控界面:

enter image description here

Hystrix 熔断器的基本用法就介绍到这里。

5、Spring Cloud Config配置中心

Spring Cloud Config 简介

Spring Cloud Config 是一个高可用的分布式配置中心,它支持将配置存放到内存(本地),也支持将其放到 Git 仓库进行统一管理(本文主要探讨和 Git 的融合)。

创建配置中心

创建配置中心一般分为以下几个步骤:

1.创建 Git 仓库。

本文为了演示实例,已经创建好了用于存放配置文件的 Git 仓库,点击这里访问。

2.创建配置中心。

在原有工程创建一个 moudle,命名为 config,在 pom.xml 加入配置中心的依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

创建启动类 Application.java:

@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

注意,要加入 @EnableConfigServer 注解,否则配置中心是无法开启的。

创建 application.yml 并增加如下内容:

server:
  port: 8888
spring:
  application:
    name: config
  profiles:
    active: dev
  cloud:
    config:
      server:
        git:
          uri: https://github.com/lynnlovemin/SpringCloudLesson.git #配置git仓库地址
          searchPaths: 第09课/config #配置仓库路径
          username: ****** #访问git仓库的用户名
          password: ****** #访问git仓库的用户密码
      label: master #配置仓库的分支
eureka:
  instance:
    hostname: ${spring.cloud.client.ipAddress}
    instanceId: ${spring.cloud.client.ipAddress}:${server.port}
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

注意这里出现了前面课程没有出现过的新配置: eureka.instance.hostname 和 eureka.instance.instanceId,我们可以通过一个测试来看这两个配置的作用。

首先分别启动注册中心 eurekaserver 和配置中心 config,浏览器访问:http://localhost:8761,我们可以看到如下界面:
enter image description here

可以看到箭头所指向的位置是以 IP:端口形式呈现的,现在我们去掉这两个配置重新启动配置中心 config,再次访问:http://localhost:8761,可以看到:

enter image description here

由此可见,它默认是以 ip:application_name:端口呈现的。

在实际项目中,建议大家都写成上述配置,否则如果通过 K8S 或 Docker 部署系统,可能会出现问题,具体原因将在第16课提到。

通过上述过程,配置服务中心已经创建完成,启动它并且访问地址:http://localhost:8888/config/dev,即可看到:

enter image description here

3.修改各个服务配置。

我们创建配置中心的目的就是为了方便其他服务进行统一的配置管理,因此,还需要修改各个服务。

以服务提供者 eurekaclient 为例,按照以下步骤进行操作。

在 pom.xml 加入配置中心依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

在 resources 下新建 bootstrap.yml 并删除 application.yml(注意:这里不是 application.yml,而是 bootstrap.yml):

spring:
  application:
    name: eurekaclient
  profiles:
    active: dev
  cloud:
    config:
      profile: dev #指定配置环境,配置文件如果是多环境则取名类似:config-dev.yml
      name: eurekaclient #指定配置文件名字(多个配置文件以英文逗号隔开)
      label: master #git仓库分支名
      discovery:
        enabled: true
        serviceId: config #连接的配置中心名字(applicaiton.name)
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

在配置中心配置的 Git 仓库相应路径下创建配置文件 eurekaclient.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8763
spring:
  application:
    name: eurekaclient

我们依次启动注册中心、配置中心和服务提供者 eurekaclient,可以看到 eurekaclient 的监听端口为8763,然后修改 eurekaclient.yml 的 server.port 为8764,重新启动 eurekaclient,可以看到其监听端口为8764,说明 eurekaclient 成功从 Git 上拉取了配置。

配置自动刷新

我们注意到,每次修改配置都需要重新启动服务,配置才会生效,这种做法也比较麻烦,因此我们需要一个机制,每次修改了配置文件,各个服务配置自动生效,Spring Cloud 给我们提供了解决方案。

手动刷新配置

我们先来看看如何通过手动方式刷新配置。

1.在 eurekaclient 工程的 pom.xml 添加依赖:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.修改远程 Git 仓库的配置文件 eurekaclient.yml:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8764
spring:
  application:
    name: eurekaclient
management:
  security:
    #关闭安全验证,否则访问refresh端点时会提示权限不足
    enabled: false

3.在 HelloController 类加入 @RefeshScope 依赖:

@RestController
@RefreshScope
public class HelloController {
 
    @Value("${server.port}")
    private int port;
 
    @RequestMapping("index")
    public String index(){
        return "Hello World!,端口:"+port;
    }
}

以上步骤就集成了手动刷新配置。下面开始进行测试。

  1. 依次启动注册中心,配置中心,客户端;
  2. 访问地址:http://localhost:8763/index,即可看到:

enter image description here

修改 Git 仓库远程配置文件 eurekaclient.yml 的端口为8764;
重新访问2的地址,我们发现端口未发生改变;
POST 方式请求地址:http://localhost:8763/refresh,如:curl -X POST http://localhost:8763/refresh,可以的客户端控制台看到如下日志信息:

enter image description here

说明 refresh 端点已请求配置中心刷新配置。 6.再次访问2的地址,可以看到:

enter image description here

  1. 我们发现端口已发生改变,说明刷新成功!

自动刷新配置

前面我们讲了通过 /refresh 端点手动刷新配置,如果每个微服务的配置都需要我们手动刷新,代价无疑是巨大的。不仅如此,随着系统的不断扩张,维护也越来越麻烦。因此,我们有必要实现自动刷新配置。

自动刷新配置原理

  1. 利用 Git 仓库的 WebHook,可以设置当有内容 Push 上去后,则通过 HTTP 的 POST 远程请求指定地址。
  2. 利用消息队列如 RabbitMQ、Kafka 等自动通知到每个微服务(本文以 RabbitMQ 为例讲解)。

实现步骤

下面我们就来实现自动刷新配置。 1.安装 RabbitMQ(安装步骤省略,请自行百度) 2.在 eurekaclient 加入如下依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

3.在 bootstrap.yml 添加以下内容:

spring:
    rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest

4.启动注册中心、配置中心和客户端;

5.POST 方式请求:http://localhost:8763/bus/refresh,可以看到配置已被刷新,实际项目中,我们会单独创建一个工程用以刷新配置,请求这个地址后,可以发现所有加入了 RefreshScope 和 actuator 依赖的工程都会被刷新配置。

6.利用 Git 的 WebHook,实现自动刷新,如图:

enter image description here

设置好刷新 URL 后,点击提交。以后每次有新的内容被提交后,会自动请求该 URL 实现配置的自动刷新。

posted @ 2024-04-20 22:05  疏影橫斜水清淺  阅读(102)  评论(0编辑  收藏  举报