实现nacos配置修改后无需重启服务--使用@RefreshScope注解

1、简介

  • @RefreshScope是 Spring Cloud 中的一个注解,主要用于实现配置的动态刷新。在微服务架构中,配置文件的更改能够即时生效,而不需要重启服务,这个注解在其中起到了关键的作用。

2、使用场景

  • 当你的微服务应用使用了配置中心(如 Spring Cloud Config)来管理配置信息时,使用@RefreshScope注解可以让标注的 Bean 在配置中心的配置发生变化时自动更新。例如,一个基于 Spring Boot 构建的微服务,它从配置中心获取数据库连接字符串、服务端口号等配置。如果在运行过程中需要修改数据库连接字符串,通过配置中心更新配置后,带有@RefreshScope注解的相关 Bean(比如数据源相关的 Bean)可以自动刷新,使得新的配置生效,而不需要重新启动整个服务。

3、工作原理

当配置中心的配置发生改变时,Spring Cloud 会发送一个RefreshEvent事件。带有@RefreshScope注解的 Bean 会监听到这个事件,然后销毁并重新创建自己。在重新创建的过程中,会重新从配置中心获取最新的配置信息,从而实现配置的动态刷新。

例如,假设有一个配置类DatabaseConfig,它使用@Configuration注解定义了一个数据源 Bean。如果这个配置类加上了@RefreshScope注解,当配置中心中与数据库连接相关的配置(如spring.datasource.url等)发生变化时,DatabaseConfig中的数据源 Bean 会被销毁并重新创建,新的数据源 Bean 会使用更新后的配置信息。

4、代码示例

以下是一个详细的使用 @RefreshScope 注解的例子,假设我们正在构建一个电商微服务应用,该应用使用了 Spring Cloud Config 作为配置中心,并且我们需要根据配置中心的配置来动态调整商品服务的一些参数,比如商品的折扣率。

  • 1、 首先,确保你的 pom.xml 中包含了必要的 Spring Cloud 依赖,例如:
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
  • 2、接下来,创建一个配置类 ProductConfig 用于读取配置中心的商品折扣率,并创建一个 ProductService 类来使用这个配置:
java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RefreshScope
public class ProductConfig {

    @Value("${product.discount.rate}")
    private double discountRate;

    @Bean
    public ProductService productService() {
        return new ProductService(discountRate);
    }
}
java 复制代码
public class ProductService {
    private final double discountRate;

    public ProductService(double discountRate) {
        this.discountRate = discountRate;
    }

    public double applyDiscount(double originalPrice) {
        return originalPrice * (1 - discountRate);
    }
}

在上述代码中:

  • ProductConfig 是一个配置类,使用了 @RefreshScope 注解,它通过 @Value("${product.discount.rate}") 从配置中心读取 product.discount.rate 属性的值,并将其注入到 discountRate 变量中。
  • ProductService 是一个服务类,它有一个 applyDiscount 方法,该方法接收商品的原始价格,并根据 discountRate 计算出折扣后的价格。
    然后,我们可以创建一个控制器类 ProductController 来使用 ProductService:
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/discount")
    public double getDiscountedPrice(@RequestParam double originalPrice) {
        return productService.applyDiscount(originalPrice);
    }
}
  • 在这个控制器中,ProductController 通过 @Autowired 注入了 ProductService,并提供了一个 /discount 的接口,该接口接收商品的原始价格作为参数,调用 ProductService 的 applyDiscount 方法计算折扣后的价格。

假设你的配置中心的配置文件 application.yml 如下:

yaml 复制代码
product:
  discount:
    rate: 0.1
  • 当你启动服务后,调用 /discount 接口,会根据 0.1(即 10%)的折扣率来计算折扣价格。例如,调用 http://localhost:8080/discount?originalPrice=100 会返回 90.0。

  • 现在,如果你想动态调整折扣率,只需要修改配置中心的 application.yml 中的 product.discount.rate 属性的值,比如将其修改为 0.2(即 20%),并触发配置刷新(例如,通过发送 POST 请求到 /actuator/refresh 端点,前提是你已经启用了 actuator),此时再次调用 /discount 接口,商品的折扣价格将根据新的折扣率进行计算。

  • 例如,再次调用 http://localhost:8080/discount?originalPrice=100,将返回 80.0,因为折扣率已经更新为 20%。

使用说明:
  • 1、首先,确保你的 Spring Cloud 应用已经正确配置并连接到配置中心。
  • 2、配置中心的配置文件(如 application.yml)中包含 product.discount.rate 属性,该属性用于设置商品的折扣率。
  • 3、ProductConfig 类中的 @RefreshScope 注解确保了 productService Bean 可以动态刷新。
  • 4、ProductService 类使用 discountRate 进行折扣计算。
  • 5、ProductController 类提供了一个 /discount 接口,接收原始价格作为参数,调用 ProductService 进行折扣计算。
  • 6、当你修改配置中心的 product.discount.rate 属性后,通过触发配置刷新(例如,使用 actuator 的 /actuator/refresh 端点),ProductService 的 discountRate 将更新,并且后续的请求将使用新的折扣率进行计算。

这样,你就可以在不重启服务的情况下,通过修改配置中心的配置,实现对商品折扣率的动态调整,这对于线上环境的灵活配置和快速响应业务变化非常有用。同时,你需要注意的是,要确保 actuator 的相关配置和 spring-cloud-starter-bus-amqp 等依赖的正确使用,以实现配置的动态刷新和事件的传播。

5、注意事项

  • 不是所有类型的 Bean 都适合使用@RefreshScope注解。例如,有状态的 Bean(如已经存储了用户会话信息等的 Bean)在重新创建时可能会丢失状态信息。对于这种情况,需要谨慎使用@RefreshScope,或者考虑在重新创建 Bean 时如何正确地处理状态信息的迁移。
  • 这个注解的使用依赖于 Spring Cloud 的配置刷新机制,所以要确保相关的配置刷新依赖已经正确引入和配置,例如spring - cloud - starter - bus - amqp(如果使用 RabbitMQ 进行配置刷新事件的传播)等相关的依赖。
相关推荐
HYUJKI15 分钟前
饿汉式单例与懒汉式单例模式
java·开发语言·单例模式
power-辰南38 分钟前
设计模式之桥接模式
java·开发语言
李歘歘1 小时前
Golang——GPM调度器
java·开发语言·后端·golang·go·秋招·春招
再拼一次吧1 小时前
final修饰的用法
java·开发语言·jvm
计算机-秋大田1 小时前
基于微信小程序的电影交流平台设计与实现(LW+源码+讲解)
java·微信小程序·小程序·课程设计
多多*1 小时前
初识JVM HotSopt 的发展历程
java·开发语言·jvm·c++·学习·算法
chian-ocean2 小时前
进程的家园:探索 Linux 地址空间的奥秘
android·java·linux
c1assy2 小时前
天机学堂3-ES+Caffeine
android·java·elasticsearch
終不似少年遊*2 小时前
通过一个算法的设计来了解栈的一些应用
java·前端·数据库
军训猫猫头2 小时前
43.Textbox的数据绑定 C#例子 WPF例子
java·c#·wpf