巧用设计模式:Apollo 打造高效稳健的配置管理体系
在当今的软件开发领域,设计模式如同建筑大师手中的蓝图,能够帮助开发者更高效、更稳健地构建复杂的软件系统。Apollo 配置中心作为一款在微服务架构中广泛应用的配置管理利器,巧妙地运用了多种设计模式,如责任链模式、单例模式、观察者模式、工厂模式、外观模式、策略模式。今天,我们就来结合源码,逐一揭秘这些设计模式在 Apollo 中的应用。
1. 单例模式
应用场景:
在整个应用程序运行期间,只需要一个实例的类,采用单例模式可以确保全局只有一个实例,节省资源,方便全局访问。
源码分析
- 客户端
ConfigService类是获取配置的入口,它内部维护了一个ConfigManager的单例实例,用于管理Config对象。
public class ConfigService {
private static final ConfigService s_instance = new ConfigService();
private volatile ConfigManager m_configManager;
private volatile ConfigRegistry m_configRegistry;
public ConfigService() {
}
// 用到了单例模式,懒加载
private ConfigManager getManager() {
if (this.m_configManager == null) {
synchronized(this) {
if (this.m_configManager == null) {
this.m_configManager = (ConfigManager)ApolloInjector.getInstance(ConfigManager.class);
}
}
}
return this.m_configManager;
}
// 用到了单例模式,懒加载
private ConfigRegistry getRegistry() {
if (this.m_configRegistry == null) {
synchronized(this) {
if (this.m_configRegistry == null) {
this.m_configRegistry = (ConfigRegistry)ApolloInjector.getInstance(ConfigRegistry.class);
}
}
}
return this.m_configRegistry;
}
}
2. 工厂模式
应用场景
工厂模式用于创建对象,将对象的创建和使用解耦,客户端不需要知道具体的创建过程。
源码分析
- 客户端
ConfigManager负责创建和管理Config对象,不同的命名空间可能需要不同的Config实例。
public class DefaultConfigManager implements ConfigManager {
private ConfigFactoryManager m_factoryManager = (ConfigFactoryManager)ApolloInjector.getInstance(ConfigFactoryManager.class);
private Map<String, Config> m_configs = Maps.newConcurrentMap();
private Map<String, ConfigFile> m_configFiles = Maps.newConcurrentMap();
public Config getConfig(String namespace) {
Config config = (Config)this.m_configs.get(namespace);
if (config == null) {
synchronized(this) {
config = (Config)this.m_configs.get(namespace);
if (config == null) {
// 获取工厂类
ConfigFactory factory = this.m_factoryManager.getFactory(namespace);
// 使用工厂类根据namespace创建具体的配置类
config = factory.create(namespace);
this.m_configs.put(namespace, config);
}
}
}
return config;
}
3. 观察者模式(Observer Pattern)
应用场景
当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。Apollo需要在配置发生变化时通知客户端或其他组件。
源码分析
- 客户端
Config接口提供了addChangeListener方法,允许注册监听器,当配置变化时,通知所有的监听器。
public interface Config {
void addChangeListener(ConfigChangeListener listener);
String getProperty(String key, String defaultValue);
}
DefaultConfig在内部维护了一个ConfigChangeListener的列表,当配置变化时,遍历并通知所有的监听器。
public class DefaultConfig implements Config {
private final List<ConfigChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
@Override
public void addChangeListener(ConfigChangeListener listener) {
m_listeners.add(listener);
}
private void fireConfigChange(ConfigChangeEvent changeEvent) {
for (ConfigChangeListener listener : m_listeners) {
listener.onChange(changeEvent);
}
}
}
4. 策略模式
应用场景
策略模式允许在运行时选择算法的实现。Apollo在配置加载、序列化等场景中,通过策略模式选择不同的实现。
源码分析:
- 客户端
ConfigFileFormat枚举了不同的配置文件格式,如Properties、XML、JSON等,不同的格式对应不同的解析策略。
public enum ConfigFileFormat {
Properties("properties"), XML("xml"), JSON("json"), @Deprecated YML("yml"), YAML("yaml"), TXT("txt");
}
ConfigFileFactory根据不同的格式,创建对应的ConfigFile实现类。
public class ConfigFileFactory {
public static ConfigFile create(String namespace, ConfigFileFormat format) {
switch (format) {
case Properties:
return new PropertiesConfigFile(namespace);
case XML:
return new XmlConfigFile(namespace);
// 其他格式
default:
throw new IllegalArgumentException("Unsupported format: " + format);
}
}
}
5. 外观模式
应用场景
外观模式为子系统中的一组接口提供了一个一致的界面,使得子系统更容易使用。ConfigService就是一个外观,为客户端提供简单的配置获取接口。
源码分析
- 客户端
ConfigService对外提供静态方法,隐藏了内部的复杂实现。
public class ConfigService {
public static Config getAppConfig() {
return getConfig(ConfigConsts.NAMESPACE_APPLICATION);
}
public static Config getConfig(String namespace) {
return getInstance().getConfig(namespace);
}
// 内部实现细节
}
6. 责任链模式
应用场景
责任链模式将请求沿着处理者链传递,直到有处理者处理它。
源码分析
- 服务端:
在Apollo服务端,有多个不同的 ReleaseMessageListener 实现类。每个实现类负责处理特定的发布消息类型或执行特定的业务逻辑。当一个发布消息被接收时,Apollo会根据责任链的逻辑,依次调用这些实现类的 handleMessage 方法。
/**
* Notify listeners with messages loaded
* @param messages
*/
private void fireMessageScanned(Iterable<ReleaseMessage> messages) {
for (ReleaseMessage message : messages) {
for (ReleaseMessageListener listener : listeners) {
try {
// 责任链
listener.handleMessage(message, Topics.APOLLO_RELEASE_TOPIC);
} catch (Throwable ex) {
Tracer.logError(ex);
logger.error("Failed to invoke message listener {}", listener.getClass(), ex);
}
}
}
}
总结
Apollo配置中心的源码中,使用了如上多种设计模式,包括但不限于单例模式、工厂模式、观察者模式、策略模式等。这些设计模式的应用,提高了系统的灵活性和可维护性,方便扩展和修改。同时,也体现了面向对象设计中的重要原则,如开闭原则、单一职责原则、依赖倒置原则等。
原文地址:https://blog.csdn.net/weixin_45593273/article/details/144324853
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!