application.properties,管理困難。service/{serviceName}/{tag}/config)。PropertySource (靜態) 與 Archaius PollResult (動態)。DynamicPropertyFactory 獲取(即時生效)@Value/Environment(需重啟)<dependency> <groupId>com.netflix.archaius</groupId> <artifactId>archaius-core</artifactId> <version>0.6.6</version> </dependency> <dependency> <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> <version>1.8</version> </dependency>
public class ConsulConfigurationSource implements PolledConfigurationSource {
private String keyName; // service/xxx/yyy/config
@Override
public PollResult poll(boolean initial, Object checkPoint) {
Consul consul = Consul.builder().build();
String kvStr = consul.keyValueClient().getValueAsString(keyName).or("");
Properties props = new Properties();
props.load(new StringReader(kvStr));
Map<String, Object> map = new HashMap<>();
for (Object k : props.keySet()) map.put((String)k, props.get(k));
return PollResult.createFull(map); // 全量刷新
}
}
預設每 60s 輪詢一次,可調 archaius.fixedDelayPollingScheduler.delayMills。
public class ConsulPropertySource extends MapPropertySource {
public ConsulPropertySource(String name, Map<String,Object> source) {
super(name, source);
// 1. 註冊到 Archaius 動態配置管理器
PolledConfigurationSource configSource = new ConsulConfigurationSource(name);
DynamicConfiguration config = new DynamicConfiguration(configSource,
new FixedDelayPollingScheduler());
ConfigurationManager.install(config);
// 2. 同步寫入 Spring PropertySource (靜態快照)
for (Iterator it = config.getKeys(); it.hasNext(); ) {
String key = (String) it.next();
this.source.put(key, config.getProperty(key));
}
}
}
public class ConsulPropertySourceBootstrapInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ctx) {
ConfigurableEnvironment env = ctx.getEnvironment();
// 移除默認 application.properties,避免干擾
env.getPropertySources().remove("applicationConfigurationProperties");
// 讀取 bootstrap.properties 獲取服務名/標籤
Properties props = PropertyUtil.loadProps("bootstrap.properties");
String name = props.getProperty("service.name");
String tag = props.getProperty("service.tag");
// 加入 Consul PropertySource
env.getPropertySources().addLast(new ConsulPropertySource(
"service/" + name + "/" + tag + "/config", new HashMap<>()));
}
}
@SpringBootApplication
public class MySpringApplication {
public void run(String[] args) {
SpringApplication sa = new SpringApplication(MySpringApplication.class);
sa.addInitializers(new ConsulPropertySourceBootstrapInitializer());
sa.addListeners(new ConsulRegisterListener()); // 服務註冊
sa.run(args);
}
}
bootstrap.properties: service.name=myserviceA service.tag=dev service.port=8080
@RestController
@RequestMapping("/test/archaius")
public class TestController {
@Autowired Environment env;
@Value("${mysql.driverClassName}") String staticVal;
@GetMapping("/xxx")
public String test() {
System.out.println("env -> " + env.getProperty("xxx"));
System.out.println("@Value -> " + staticVal);
// 動態獲取(即時感知 Consul 變更)
DynamicStringProperty dyn = DynamicPropertyFactory.getInstance()
.getStringProperty("hystrix.command.xxx.timeoutInMilliseconds", "default");
System.out.println("Dynamic -> " + dyn.get());
return "hello";
}
}
ApplicationContextInitializer 階段注入 PropertySource。這套方案實現了「配置集中存、動態刷新、業務無感」,是微服務治理的關鍵基礎設施。