Architecture
This document describes the architecture design and core components of Apq.Cfg.
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ cfg["key"] │ │ cfg.SetValue() │ │ cfg.ConfigChanges │ │
│ │ cfg.GetSection() │ cfg.SaveAsync() │ (Rx Observable) │ │
│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
└─────────┼────────────────┼─────────────────────┼────────────────┘
│ │ │
┌─────────▼────────────────▼─────────────────────▼────────────────┐
│ ICfgRoot Interface │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ MergedCfgRoot ││
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ ││
│ │ │ Level Merge │ │ Pending │ │ ChangeCoordinator │ ││
│ │ │ │ │ Queue │ │ │ ││
│ │ └─────────────┘ └─────────────┘ └─────────────────────┘ ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
│ │ │
┌─────────▼────────────────▼─────────────────────▼────────────────┐
│ Source Layer (ICfgSource) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ JSON │ │ YAML │ │ Consul │ │ Nacos │ │ Vault │ │
│ │ Level:0 │ │ Level:1 │ │ Level:10│ │ Level:10│ │ Level:15│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
└───────┼──────────┼──────────┼──────────┼──────────┼─────────────┘
│ │ │ │ │
┌───────▼──────────▼──────────▼──────────▼──────────▼─────────────┐
│ Microsoft.Extensions.Configuration │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ IConfigurationRoot (Merged Config) ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘Core Components
ICfgRoot Interface
The main entry point for the configuration system.
csharp
public interface ICfgRoot : IDisposable, IAsyncDisposable
{
// Indexer
string? this[string key] { get; set; }
// Read operations
T? GetValue<T>(string key);
bool Exists(string key);
ICfgSection GetSection(string key);
// Write operations
void SetValue(string key, string? value, int? targetLevel = null);
void Remove(string key, int? targetLevel = null);
Task SaveAsync(int? targetLevel = null, CancellationToken ct = default);
// Batch operations
IReadOnlyDictionary<string, string?> GetMany(IEnumerable<string> keys);
void SetManyValues(IEnumerable<KeyValuePair<string, string?>> values, int? targetLevel = null);
// Events
IObservable<ConfigChangeEvent> ConfigChanges { get; }
}ICfgSource Interface
Base interface for all configuration sources.
csharp
public interface ICfgSource
{
string Name { get; set; } // Source name
int Level { get; } // Level priority
string Type { get; } // Source type
bool IsWriteable { get; } // Is writable
bool IsPrimaryWriter { get; } // Is primary writer
int KeyCount { get; } // Total key count
int TopLevelKeyCount { get; } // Top-level key count
IConfigurationSource BuildSource();
IEnumerable<KeyValuePair<string, string?>> GetAllValues();
}
public interface IWritableCfgSource : ICfgSource
{
Task ApplyChangesAsync(IReadOnlyDictionary<string, string?> changes, CancellationToken ct);
}Level Merge Mechanism
Configuration sources are merged by level, with higher levels taking precedence:
Level 0: config.json (base configuration)
Level 1: config.{env}.json (environment-specific)
Level 2: config.local.json (local overrides)
Level 10: Consul/Nacos/Etcd (remote configuration)
Level 15: Vault (secrets)
Level 20: Environment Variables (highest priority)Hot Reload Mechanism
┌─────────────────────────────────────────────────────────────┐
│ ChangeCoordinator │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Debounce │ │ Incremental │ │ Change Notification │ │
│ │ (100ms) │ │ Update │ │ (ConfigChanges) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
└─────────┼────────────────┼─────────────────────┼────────────┘
│ │ │
▼ ▼ ▼
File Change Source Reload Rx ObservableThread Safety
- Read operations: Lock-free, using immutable data structures
- Write operations: ConcurrentDictionary for pending data
- Save operations: Per-source locking
- Hot reload: Debounce + atomic replacement
Next Steps
- Encryption Design - Encryption architecture
- Extension Development - Create custom sources