文章目录
- 前言
- 一、SpringBoot集成apollo源码分析
-
-
- 1. spring.factories
-
- 1.1 ApolloAutoConfiguration解析
- 1.2ApolloApplicationContextInitializer解析
-
- 1.2.1 ApolloApplicationContextInitializer#postProcessEnvironment
- 1.2.2 ApolloApplicationContextInitializer#initialize
-
- 1.2.2.1 configPropertySourceFactory#getConfigPropertySource
- 1.2.2.2 ConfigService#getConfig
- 1.2.2.2 DefaultConfigManager#getConfig
- 1.2.2.3 DefaultConfigFactory#create
- 1.2.2.4 DefaultConfigFactory#createLocalConfigRepository
- 1.2.2.5 LocalFileConfigRepository构造方法
- 1.2.2.6 LocalFileConfigRepository#setUpstreamRepository
- 1.2.2.7 LocalFileConfigRepository#trySync
- 2. apollo配置属性注入
-
前言
这里就不说
SpringBoot自动装备的原理,Apollo与SpringBoot的整合就是借助了SpringBoot的SPI机制,下面我们来看下处理流程
一、SpringBoot集成apollo源码分析
1. spring.factories
我们都知道
spring.factories是SpringBoot的扩展点,是实现自动装配的核心原理,Apollo客户端就是借助这个SPI机制与SpringBoot整合,我们看下apollo的jar包中的META-INFO/spring.factories文件
1.1 ApolloAutoConfiguration解析
这里看名字是实现
apollo的自动配置,在配置类中会判断如果spring中没有PropertySourcesProcessor这个bean,那么他会new一个ConfigPropertySourcesProcessor到容器中,确保这个bean一定存在,这个bean的作用我们后续会解析

1.2ApolloApplicationContextInitializer解析
ApolloApplicationContextInitializer实现了两个接口ApplicationContextInitializer和EnvironmentPostProcessor,Spring Boot启动过程,会先调用EnvironmentPostProcessor.postProcessEnvironment方法,再调用ApplicationContextInitializer.initialize方法。也就是Spring Boot优先准备环境,再初始化容器。
1.2.1 ApolloApplicationContextInitializer#postProcessEnvironment
这里首先就是检查
apollo.bootstrap.eagerLoad.enabled属性,判断是否允许在Spring启动初期加载apollo配置,如果允许则继续检查apollo.bootstrap.enabled属性判断是否允许加载apollo,如果都允许,则调用initialize方法进行初始化
@Override
public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {
// should always initialize system properties like app.id in the first place
initializeSystemProperty(configurableEnvironment);
Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, Boolean.class, false);
//EnvironmentPostProcessor should not be triggered if you don't want Apollo Loading before Logging System Initialization
if (!eagerLoadEnabled) {
return;
}
Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false);
if (bootstrapEnabled) {
DeferredLogger.enable();
//初始化Apollo的配置
initialize(configurableEnvironment);
}
}
1.2.2 ApolloApplicationContextInitializer#initialize
- 这里会发现他从
apollo.bootstrap.namespaces属性配置中获取namespaces,然后遍历命名空间列表,调用ConfigService$getConfig拉取远程配置,然后将拉取到的配置包装成PropertySource,然后将包装好的PropertySource添加到CompositePropertySource内部,最后CompositePropertySource属性源包装类添加到Spring 的 Environment环境中,注意是插入在属性源列表的头部,因为取属性的时候其实是遍历这个属性源列表来查找,找到即返回,所以出现同名属性是以前面的为准
protected void initialize(ConfigurableEnvironment environment) {
if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
//already initialized, replay the logs that were printed before the logging system was initialized
DeferredLogger.replayTo();
return;
}
String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
CompositePropertySource composite;
final ConfigUtil configUtil = ApolloInjector.getInstance(ConfigUtil.class);
if (configUtil.isPropertyNamesCacheEnabled()) {
composite = new CachedCompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
} else {
composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
}
for (String namespace : namespaceList) {
//获取配置
Config config = ConfigService.getConfig(namespace);
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
environment.getPropertySources().addFirst(composite);
}
1.2.2.1 configPropertySourceFactory#getConfigPropertySource
- 将
Apollo的Config封装成Spring Config的ConfigPropertySource对象- 将新生成的
ConfigPropertySource对象添加到内部列表,方便后续为每个配置实例添加配置变化监听器。
public ConfigPropertySource getConfigPropertySource(String name, Config source) {
//将Apollo的Config配置封装为继承自Spring内置的EnumerablePropertySource类的ConfigPropertySource对象
ConfigPropertySource configPropertySource = new ConfigPropertySource(name, source);
//将新生成的ConfigPropertySource对象缓存到内部列表,以备后续为每个配置实例添加配置变化监听器使用。
configPropertySources.add(configPropertySource);
return configPropertySource;
}
1.2.2.2 ConfigService#getConfig
- 这里
getManager去获取ConfigManager实例,采用了java的ServiceLoader机制,是SPI机制- 这里看
ConfigManager的实现类其实只有一个,就是DefaultConfigManager
public static Config getConfig(String namespace) {
return s_instance.getManager().getConfig(namespace);
}
private ConfigManager getManager() {
//双重检查锁防止重复创建
if (m_configManager == null) {
synchronized (this) {
if (m_configManager == null) {
//使用ApolloInjector获取ConfigManager实例,这里是采用了java的ServiceLoeader机制
m_configManager = ApolloInjector.getInstance(ConfigManager.class);
}
}
}
return m_configManager;
}
1.2.2.2 DefaultConfigManager#getConfig
- 这里首先从缓存中获取配置,缓存中没有则从远程拉取
- 这里使用
SPI机制获取Factory,默认是DefaultConfigFactory,这里会调用DefaultConfigFactory#create从远程拉取配置
public Config getConfig(String namespace) {
Config config = m_configs.get(namespace);
if (config == null) {
synchronized (this) {
config = m_configs.get(namespace);
if (config == null) {
//这里Factory创建也使用了ServiceLoader机制,默认是DefaultConfigFactory
ConfigFactory factory = m_factoryManager.getFactory(namespace);
config = factory.create(namespace);
m_configs.put(namespace, config);
}
}
}
return config;
}
1.2.2.3 DefaultConfigFactory#create
1.这里重点是首先调用
createLocalConfigRepository(namespace)会创建LocalConfigRepository,在createLocalConfigRepository()方法中又会调用createRemoteConfigRepository(namespace)创建RemoteConfigRepository,最后又会调用createRepositoryConfig创建DefaultConfig对象,内部持有LocalConfigRepository
2. 对象创建时序:DefaultConfig -> LocalFileConfigRepository -> RemoteConfigRepository
3. 对象关系:DefaultConfig -> 持有 LocalFileConfigRepository, LocalFileConfigRepository -> 持有 RemoteConfigRepository
3. 配置变化传播时序:RemoteConfigRepository -> LocalFileConfigRepository

本文详细解读了SpringBoot如何与Apollo集成,涉及自动配置、SpringValue处理器、配置属性注入和变更监听机制。重点解析了ApolloAutoConfiguration、ApplicationContextInitializer和关键组件的工作流程,以及配置属性如何自动更新到Spring应用中。

最低0.47元/天 解锁文章
3652

被折叠的 条评论
为什么被折叠?



