手写@RefreshScope,很简单嘛!

文摘   2024-10-26 10:00   新疆  

最新实战案例锦集:《Spring Boot3实战案例合集》持续更新,每天至少更新一篇文章,订阅后将赠送文章最后展示的所有MD文档(学习笔记)。

环境:Spring Boot 3.2.5



1. 简介

在生产环境中,实现不停机修改配置并实时生效的需求至关重要。该需求旨在确保系统能够持续提供服务,同时允许运维人员在不影响业务连续性的前提下,灵活调整系统配置。通过实现这一需求,运维人员可以更加高效地管理Spring Boot应用,提升系统的整体性能和稳定性。

如果你的项目使用到了Spring Cloud那么通过它提供的Actuator端点 /refresh 实现配置的动态刷新。

本篇文章将带你亲手实现配置的实时刷新功能,而无需借助 Spring Cloud。

我们将完成以下内容:

  • 自定义作用域及注解 @RefreshScope

    设计并实现一个自定义的作用域,使得带有 @RefreshScope 注解的 Bean 能够在配置更新时重新加载。

  • 更新 application.yml 或 properties 配置文件

    实现如何在配置文件的配置项发生变化后能被应用识别。

  • 刷新带有 @RefreshScope 的 Bean

    如何在配置更新后触发特定的事件,从而重新初始化带有 @RefreshScope 注解的 Bean,使其立即生效。

     

2. 实战案例

 因为是自己手写实现,所以我们不需要引入任何其它的依赖。

2.1 自定义作用域

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Scope("refresh")public @interface RefreshScope {
@AliasFor(annotation = Scope.class) ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}

这里你可以不定义 proxyMode,而是在 @Scope 中直接定义好 proxyMode 属性值。不过那样不够灵活,如果需要自定义还得修改源码。

接下来,我们还需要定义自定义作用域 @RefreshScope 对应的 Scope 对象,因为最终获取使用该注解的bean 将会通过该Scope

public class RefreshScope implements Scope, DisposableBean {
private final Logger logger = LoggerFactory.getLogger(getClass()) ;
  private Map<String, BeanLifecycleWrapper> cache = new ConcurrentHashMap<>() ; @Override public Object get(String name, ObjectFactory<?> objectFactory) { BeanLifecycleWrapper wrapper = cache.computeIfAbsent(name, key -> new BeanLifecycleWrapper(name, objectFactory)) ; return wrapper.getBean() ; }
@Override public Object remove(String name) { return cache.remove(name) ;  } public void registerDestructionCallback(String name, Runnable callback) { // TODO  } public Object resolveContextualObject(String key) { return key ;  } public String getConversationId() { return null ; }}

在解释上面代码前,我们应该先来了解下Bean的不同作用域是如何被创建的。

Spring全家桶实战案例源码
spring, springboot, springcloud 案例开发详解
 最新文章