近日在工作中修改applicition.yml配置文件时,使用到@HeraclesDynamicConfig自定义注解可以动态读取配置文件修改内容,不需要启动服务器。便想记录一下底层的实现原理。
1.区别
-
@Value 注解:
@Value
注解是 Spring 框架提供的用于从配置文件中读取值并注入到 Spring Bean 中的注解。它在应用启动时将配置文件中的值注入到对应的属性中,但一旦注入后,这些值通常被视为静态的,不会再动态更新。- 当配置文件(如
application.properties
或application.yml
)中的值发生变化时,Spring 不会自动感知这些变化并更新已经注入的 Bean 属性。因此,需要重新启动应用程序来使新的配置值生效。
-
自定义注解:
自定义
注解的设计可能不同于 Spring 的@Value
注解。它可能利用了额外的机制或后台服务,能够在运行时动态地读取配置文件的变化,并将新的配置值注入到应用程序中,而无需重新启动服务器。- 这种实现可以借助后台线程、定时任务或监听器等机制,实时地监测配置文件的变化,并通过反射或其他手段更新被自定义注解标注的字段或属性。
2.底层实现
1. 自定义注解定义
首先,定义一个自定义注解,比如 @HeraclesDynamicConfig
,它可以被应用到类、方法或字段上,以标记需要动态更新的配置属性。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface HeraclesDynamicConfig {
String value();
}
2. 配置监听器
使用 Spring Boot 或其他框架的监听器来监听配置文件的变化。Spring Boot 提供了 ApplicationListener
接口和 ApplicationEvent
类,可以用来监听特定事件,如 EnvironmentChangeEvent
。
1import org.springframework.context.ApplicationListener;
2import org.springframework.context.event.ContextRefreshedEvent;
3import org.springframework.core.env.ConfigurableEnvironment;
4
5public class ConfigChangeListener implements ApplicationListener<ContextRefreshedEvent> {
6
7 private final ConfigurableEnvironment environment;
8
9 public ConfigChangeListener(ConfigurableEnvironment environment) {
10 this.environment = environment;
11 }
12
13 @Override
14 public void onApplicationEvent(ContextRefreshedEvent event) {
15 // 在这里检查和更新配置
16 if (event.getApplicationContext().getParent() == null) {
17 // 检查 application.properties/yml 更新
18 reloadConfiguration();
19 }
20 }
21
22 private void reloadConfiguration() {
23 // 重新加载配置
24 }
25}
3. 实现动态配置更新
在 reloadConfiguration
方法中,你需要实现从配置文件中读取配置并更新应用程序状态的逻辑。这可能涉及到对 ConfigurableEnvironment
的使用,以及将新的配置值反射到你的应用程序中。
4. 注解处理器
创建一个后处理(PostProcessor)或切面(Aspect),它会在运行时检查带有 @HeraclesDynamicConfig
注解的元素,并根据最新的配置文件内容更新它们。
1import org.aspectj.lang.ProceedingJoinPoint;
2import org.aspectj.lang.annotation.Around;
3import org.aspectj.lang.annotation.Aspect;
4import org.springframework.beans.factory.annotation.Autowired;
5import org.springframework.stereotype.Component;
6
7@Aspect
8@Component
9public class HeraclesDynamicConfigAspect {
10
11 @Autowired
12 private ConfigChangeListener configChangeListener;
13
14 @Around("@annotation(HeraclesDynamicConfig)")
15 public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
16 // 在调用方法之前检查配置是否已更新
17 configChangeListener.reloadConfiguration();
18 return joinPoint.proceed();
19 }
20}
5. 使用自定义注解
在你的代码中使用 @HeraclesDynamicConfig
注解来标记那些需要动态更新配置的字段或方法。
1@Service
2public class MyService {
3
4 @Value("${my.property}")
5 @HeraclesDynamicConfig("my.property")
6 private String myProperty;
7
8 // ...
9}
请注意,以上只是小编记录的底层实现原理,尚未实操,如有需要还请结合实际。但大致的实现方法就是如此了。欢迎大家留言更好用的框架。