在当今的软件开发领域,设计模式如同建筑大师手中的蓝图,能够帮助开发者更高效、更稳健地构建复杂的软件系统。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();@Overridepublic 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配置中心的源码中,使用了如上多种设计模式,包括但不限于单例模式、工厂模式、观察者模式、策略模式等。这些设计模式的应用,提高了系统的灵活性和可维护性,方便扩展和修改。同时,也体现了面向对象设计中的重要原则,如开闭原则、单一职责原则、依赖倒置原则等。