自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

運行時修改 Spring Boot 屬性的 N 種方式

開發(fā) 前端
application.properties文件是靜態(tài)的,應(yīng)用不重啟的情況下就無法更改。然而,Spring Boot ? ?提供了幾種強大的方法來在運行時調(diào)整配置,而無需停機。無論是在實時應(yīng)用中功能切換,還是更改第三方相關(guān)配置都無需重啟應(yīng)用。

環(huán)境:Spring Boot3.2.5

1. 簡介

在許多實際場景中,動態(tài)管理應(yīng)用程序配置可能是一個關(guān)鍵需求。在微服務(wù)架構(gòu)中,由于某些操作,不同的服務(wù)可能需要實時配置更改。應(yīng)用可能需要根據(jù)用戶環(huán)境、外部API的數(shù)據(jù)或遵守動態(tài)變化的要求來調(diào)整其行為。

application.properties文件是靜態(tài)的,應(yīng)用不重啟的情況下就無法更改。然而,Spring Boot    提供了幾種強大的方法來在運行時調(diào)整配置,而無需停機。無論是在實時應(yīng)用中功能切換,還是更改第三方相關(guān)配置都無需重啟應(yīng)用。

本篇文章將介紹幾種在不直接修改application.properties文件的情況下,動態(tài)更新 Spring Boot 應(yīng)用程序中屬性的策略。

2. 實戰(zhàn)案例

2.1 將Bean定義為Prototype作用域

當我們需要在不影響已創(chuàng)建的 Bean 實例或不改變?nèi)謶?yīng)用程序狀態(tài)的情況下動態(tài)調(diào)整特定 Bean 的屬性時,直接注入帶有@Value 注解的 @Service類是不行的,因為這些屬性在應(yīng)用程序上下文的生命周期中是靜態(tài)的,簡單說注入是一次性的。

我們可以使用@Configuration 配置類中的@Bean方法創(chuàng)建具有可修改屬性的 Bean。這種方法允許在應(yīng)用程序執(zhí)行過程中動態(tài)更改屬性:

@Configuration
public class AppConfig {


  @Bean
  // 聲明為多例bean作用域
  @Scope("prototype")
  public UserService userService(@Value("${pack.app.title:}") String title) {
    return new UserService(title) ;
  }
}
public class UserService {
  private final String title;


  public UserService(String title) {
    this.title= title;
  }
  // getters, setters
}

通過@Scope將UserService作用域聲明為多例,這樣能保證每次通過getBean都拿到的是一個新的對象,既然是新對象那么每次都會重新注入title值。如下示例:

@RestController
public class UserController {
  @Resource
  private ApplicationContext context; 
  @Resource
  private ApplicationContext context ;
  @GetMapping("/update")
  public String update() {
    // 設(shè)置系統(tǒng)屬性值;
    // 注意你不能吧屬性定義在application.yml配置文件中
    System.setProperty("pack.app.title", "xxxooo - " + new Random().nextInt(10000)) ;
    return "update success" ;
  }
  @GetMapping("/title")
  public String title() {
    return this.context.getBean("us", UserService.class).getTitle() ;
  }
}

每次都是getBean獲取新對象,所以屬性title每次注入的都是最新的值。

2.2 使用@RefreshScope

我們可以使用 Spring Cloud 的@RefreshScope注解和/actuator/refresh端點。該接口會刷新所有@RefreshScopeBean,其實此種方式與上面2.1類似,首先是將bean對象生成代理,再通過代理對象執(zhí)行時每次都重新獲取getBean,以此來達到實時更新屬性。

引入依賴

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

開啟refresh接口

management:
  endpoint:
    refresh:
      enabled: true
  endpoints:
    web:
      exposure:
        include: refresh

如果你想在每次調(diào)用該接口時都記錄日志,進行如下日志級別設(shè)置:

logging:
  level:
    org.springframework.boot.actuate: debug

以上配置完成后,接下來就可以定義需要實時刷新的bean對象了;

@RefreshScope
@Component
public class AppComponent {
  @Value("${pack.app.title:}")
  private String title ;


  public String getTitle() {
    return this.title ;
  }
}

接下來需要完成的是,動態(tài)向Environment中添加PropertySource該對象中存入的是我們需要動態(tài)刷新的值。

@Service
public class PackPropertyService {
  private static final String PACK_PROPERTIES_SOURCE_NAME = "packDynamicProperties" ;


  private final ConfigurableEnvironment environment ;
  public PackPropertyService(ConfigurableEnvironment environment) {
    this.environment = environment ;
  }
  // 更新或者添加PropertySource操作
  public void updateProperty(String key, String value) {
    MutablePropertySources propertySources = environment.getPropertySources() ;
    if (!propertySources.contains(PACK_PROPERTIES_SOURCE_NAME)) {
      Map<String, Object> properties = new HashMap<>() ;
      properties.put(key, value) ;
      propertySources.addFirst(new MapPropertySource(PACK_PROPERTIES_SOURCE_NAME, properties)) ;
    } else {
      // 替換更新值
      MapPropertySource propertySource = (MapPropertySource) propertySources.get(PACK_PROPERTIES_SOURCE_NAME) ;
      propertySource.getSource().put(key, value) ;
    }
  }
}

接下來寫一個接口進行更新屬性值;

@RestController
@RequestMapping("/configprops")
public class PropertyController {
    
  private final PackPropertyService pps ;
  private final AppComponent app ;
  public PropertyController(PackPropertyService pps, AppComponent app) {
    this.pps = pps ;
    this.app = app ;
  }
    
  @PostMapping("/update")
  public String updateProperty(String key, String value) {
    pps.updateProperty(key, value) ;
    return "update success" ;
  }
  @GetMapping("/title")
  public String title() {
    return app.getTitle() ;
  }
}

首先調(diào)用/configprops/update接口更新屬性,接著調(diào)用 /actuator/refresh 接口進行刷新操作,最后調(diào)用/configprops/title接口時,AppComponent代理對象會會使用更新的配置屬性重新初始化 Bean。

2.3 使用外部配置文件

在某些情況下,有必要在應(yīng)用程序部署包之外管理配置更新,以確保對屬性進行持續(xù)更改。這也允許我們將更改分發(fā)給多個應(yīng)用程序。

在本例中,我將使用與之前相同的 Spring Cloud 設(shè)置來啟用@RefreshScope和/actuator/refresh支持。我們使用外部文件external-config.properties。

我們還是借助上面的/configprops/title接口訪問屬性,通過 /actuator/refresh 接口屬性配置。

我們需要做的是在啟動服務(wù)是添加如下啟動參數(shù),指定外部配置文件

圖片圖片

初始文件內(nèi)容;

pack.app.title=xxxooo

圖片圖片

當我們修改次文件內(nèi)容后,直接調(diào)用/actuator/refresh 接口;

圖片圖片

返回了已經(jīng)更新的配置屬性key,再次訪問/title接口;

圖片圖片

得到了最新的值。

責任編輯:武曉燕 來源: Spring全家桶實戰(zhàn)案例源碼
相關(guān)推薦

2015-07-20 15:44:46

Swift框架MJExtension反射

2020-09-28 15:54:18

Python語言技術(shù)

2024-03-21 09:15:58

JS運行的JavaScrip

2020-12-07 13:31:43

GoMutex開發(fā)者

2019-07-12 09:30:12

DashboardDockerDNS

2021-09-11 15:38:23

容器運行鏡像開放

2022-05-09 07:20:10

監(jiān)控項目工具

2024-01-29 08:07:42

FlinkYARN架構(gòu)

2023-08-27 21:07:02

2023-08-21 09:37:57

MySQL工具MariaDB

2021-08-18 08:32:09

代碼運行時間示波器

2013-11-26 16:49:55

Android開發(fā)運行時KitKat

2023-01-03 09:10:21

2023-07-28 10:42:43

2024-03-20 10:46:00

云原生容器

2022-01-19 08:50:53

設(shè)備樹Linux文件系統(tǒng)

2023-02-12 12:00:57

2023-08-29 08:20:35

Kubernete跨云容器

2021-08-27 00:21:19

JSJust源碼

2022-12-30 08:08:30

點贊
收藏

51CTO技術(shù)棧公眾號