Tomcat、Netty、Dubbo 等框架皆採用「微內核 + 配置驅動」架構。配置來源多樣 (本地 XML/Properties/YAML、遠程配置中心、數據庫、環境變量),格式各異。本文設計一套**可擴展、類型安全、多源融合**的配置加載機制:核心接口 IConfigLoader<T>、來源抽象 IConfigProvider<S>、工廠 ConfigProviderFactory、抽象基類 AbstractConfigLoader,並演示 MarketConfig 多源加載實戰。
public interface IConfigLoader {
/**
* 加載配置並轉換為目標類型 T
* @return 配置對象
* @throws ConfigException 加載/解析/轉換失敗
*/
T load() throws ConfigException;
}
泛型 T:聲明加載目標類型 (如 MarketConfig),調用端類型安全獲取。
public interface IConfigProvider {
/**
* 提供原始配置源對象 (Document, Properties, Yaml, InputStream 等)
* @return 來源對象
* @throws ConfigException 讀取失敗
*/
S provide() throws ConfigException;
}
泛型 S:聲明來源對象類型,解耦加載器與具體解析庫 (DOM、SnakeYAML、Hocon 等)。
public final class ConfigProviderFactory {
private ConfigProviderFactory() { throw new UnsupportedOperationException(); }
public static IConfigProvider createDocumentProvider(String filePath) {
return new DocumentProvider(filePath); // DOM 解析 XML
}
public static IConfigProvider createPropertiesProvider(String filePath) {
return new PropertiesProvider(filePath); // Properties 文件
}
public static IConfigProvider createYamlProvider(String filePath) {
return new YamlProvider(filePath); // SnakeYAML
}
// 遠程配置中心提供者
public static IConfigProvider createNacosProvider(String dataId, String group) {
return new NacosConfigProvider(dataId, group);
}
}
public abstract class AbstractConfigLoader implements IConfigLoader {
protected final IConfigProvider provider;
protected AbstractConfigLoader(IConfigLoader provider) { // 修正:應為 IConfigProvider
this.provider = provider;
}
// 模板方法:統一異常處理、日誌、監控切入點
@Override
public final T load() throws ConfigException {
try {
S source = provider.provide();
return load(source);
} catch (ConfigException e) {
throw e;
} catch (Exception e) {
throw new ConfigException("Load config failed: " + provider.getClass().getSimpleName(), e);
}
}
// 子類實現:具體解析邏輯
protected abstract T load(S source) throws ConfigException;
protected IConfigProvider getProvider() { return provider; }
}
public class MarketConfig {
private AppleConfig appleConfig;
private EggConfig eggConfig;
private OwnerConfig ownerConfig;
// getter/setter
}
public class AppleConfig { private int price; private String color; /* getter/setter */ }
public class EggConfig { private int weight; /* getter/setter */ }
public class OwnerConfig {
private Map owners = new HashMap<>();
public void addOwner(String port, String owner) { owners.put(port, owner); }
public String getOwner(String port) { return owners.get(port); }
public Map getAll() { return Collections.unmodifiableMap(owners); }
}
public class MarketConfigLoader extends AbstractConfigLoader {
public MarketConfigLoader(IConfigProvider provider) { super(provider); }
@Override
protected MarketConfig load(Document doc) throws ConfigException {
MarketConfig config = new MarketConfig();
// XPath 或 DOM 遍歷解析
Element root = doc.getDocumentElement();
config.setAppleConfig(parseApple(root));
config.setEggConfig(parseEgg(root));
// OwnerConfig 來自 Properties,委託給專用 Loader
OwnerConfigLoader ownerLoader = new OwnerConfigLoader(
ConfigProviderFactory.createPropertiesProvider("config/owner.properties"));
config.setOwnerConfig(ownerLoader.load());
return config;
}
// parseApple, parseEgg 省略...
}
public class OwnerConfigLoader extends AbstractConfigLoader {
public OwnerConfigLoader(IConfigProvider provider) { super(provider); }
@Override
protected OwnerConfig load(Properties props) throws ConfigException {
OwnerConfig config = new OwnerConfig();
props.forEach((k, v) -> config.addOwner((String) k, (String) v));
return config;
}
}
public class ConfigBootstrap {
public static void main(String[] args) {
// XML 來源
IConfigProvider xmlProvider = ConfigProviderFactory.createDocumentProvider("config/market.xml");
MarketConfigLoader marketLoader = new MarketConfigLoader(xmlProvider);
MarketConfig marketConfig = marketLoader.load(); // 類型安全獲取
System.out.println("Apple price: " + marketConfig.getAppleConfig().getPrice());
System.out.println("Owner port1: " + marketConfig.getOwnerConfig().getOwner("port1"));
}
}
public class MergedConfigLoader implements IConfigLoader {
private final List> loaders; // 按優先級排序
private final Merger merger; // 合併策略
public MergedConfigLoader(List> loaders, Merger merger) {
this.loaders = loaders; this.merger = merger;
}
@Override
public T load() throws ConfigException {
T result = null;
for (IConfigLoader loader : loaders) {
T partial = loader.load();
result = (result == null) ? partial : merger.merge(result, partial);
}
return result;
}
}
// 合併策略接口
public interface Merger { T merge(T base, T override); }
public interface ConfigChangeListener {
void onChange(T oldConfig, T newConfig);
}
public class HotReloadConfigLoader implements IConfigLoader, Runnable {
private final IConfigLoader delegate;
private final long intervalMs;
private final List> listeners = new CopyOnWriteArrayList<>();
private T currentConfig;
private volatile boolean running = true;
public HotReloadConfigLoader(IConfigLoader delegate, long intervalMs) {
this.delegate = delegate; this.intervalMs = intervalMs;
this.currentConfig = delegate.load();
}
@Override public T load() { return currentConfig; }
@Override public void run() {
while (running) {
try { Thread.sleep(intervalMs); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); break; }
try {
T newConfig = delegate.load();
if (!Objects.equals(currentConfig, newConfig)) {
T old = currentConfig;
currentConfig = newConfig;
listeners.forEach(l -> l.onChange(old, newConfig));
}
} catch (Exception e) { log.error("Hot reload failed", e); }
}
}
public void addListener(ConfigChangeListener l) { listeners.add(l); }
public void stop() { running = false; }
}
@Configuration
@EnableConfigurationProperties
public class ConfigLoaderAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ConfigProviderFactory configProviderFactory() {
return new ConfigProviderFactory(); // 無狀態工廠
}
@Bean
public MarketConfig marketConfig(ConfigProviderFactory factory) throws ConfigException {
return new MarketConfigLoader(factory.createDocumentProvider("config/market.xml")).load();
}
@Bean
public HotReloadConfigLoader hotMarketConfig(MarketConfig initial) {
HotReloadConfigLoader loader = new HotReloadConfigLoader<>(
new MarketConfigLoader(ConfigProviderFactory.createDocumentProvider("config/market.xml")),
30_000); // 30s 輪詢
loader.addListener((o, n) -> log.info("MarketConfig reloaded"));
new Thread(loader, "config-hot-reload").start();
return loader;
}
}
IConfigProvider (源) → IConfigLoader (轉換) → 業務對象,單一職責。AbstractConfigLoader 統一異常、日誌、監控。IConfigProvider,不動加載器。Merger 接口支援覆蓋、深度合併、數組追加等多種語義。HotReloadConfigLoader 裝飾器模式無侵入增強。配置加載機制的核心價值在於:**屏蔽來源差異、提供類型安全視圖、支援多源融合與動態更新**。本文設計的 Provider-Loader-Factory 三層架構,配合泛型、模板方法、裝飾器模式,實現了高內聚、低耦合、易擴展的配置加載體系,可直接應用於框架開發、微服務配置中心客戶端、複雜應用啟動器等場景。