题目
设计支持多数据源动态切换和扩展的配置中心系统
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
抽象工厂模式,动态代理,类加载机制,设计模式综合应用
快速回答
实现支持多数据源动态切换的配置中心需结合多种设计模式:
- 使用抽象工厂模式创建不同数据源的配置客户端
- 通过动态代理实现数据源切换和懒加载
- 利用类加载机制实现客户端热部署
- 结合策略模式管理数据源访问策略
问题场景
在分布式系统中,需要从不同数据源(ZooKeeper、Nacos、Redis)动态加载配置,且需满足:
1. 运行时动态切换数据源
2. 不重启服务扩展新数据源
3. 统一客户端接口隔离实现差异
核心解决方案
1. 抽象工厂模式创建客户端
// 抽象产品
interface ConfigClient {
String getConfig(String key);
}
// 具体产品
class ZkConfigClient implements ConfigClient {
public String getConfig(String key) { /* ZK实现 */ }
}
// 抽象工厂
interface ClientFactory {
ConfigClient createClient();
}
// 具体工厂
class ZkClientFactory implements ClientFactory {
public ConfigClient createClient() {
return new ZkConfigClient();
}
}2. 动态代理实现切换
class DynamicClientProxy implements InvocationHandler {
private ConfigClient currentClient;
public Object invoke(Object proxy, Method method, Object[] args) {
// 实际调用当前数据源客户端
return method.invoke(currentClient, args);
}
// 动态切换方法
public void switchDataSource(DataSourceType type) {
this.currentClient = ClientFactoryRegistry.getFactory(type).createClient();
}
}
// 使用示例
DynamicClientProxy proxy = new DynamicClientProxy();
ConfigClient client = (ConfigClient) Proxy.newProxyInstance(...);
client.switchDataSource(DataSourceType.NACOS); // 运行时切换3. 类加载实现热扩展
// 新数据源扩展步骤:
// 1. 实现ConfigClient和ClientFactory
// 2. 打包成JAR放入ext目录
// 3. 动态加载:
URLClassLoader loader = new URLClassLoader(new URL[]{jarUrl});
ClientFactory factory = (ClientFactory) loader.loadClass("com.xxx.CustomFactory").newInstance();
ClientFactoryRegistry.register(factory);最佳实践
- 双重校验锁保证工厂注册线程安全
- 代理类添加熔断机制处理数据源故障
- 使用SPI机制替代反射加载提高扩展性
常见错误
- 未清理类加载器导致元空间泄漏
- 动态代理未处理受检异常
- 缺少回退策略导致切换失败阻塞
扩展知识
- 结合Spring:通过BeanPostProcessor集成动态代理
- 性能优化:客户端连接池管理
- 安全考虑:类加载白名单机制