......
public class ApolloApplicationContextInitializer implements
public class ApolloApplicationContextInitializer implements
// 这个接口允许在ConfigurableApplicationContext(如AnnotationConfigApplicationContext或XmlWebApplicationContext等)刷新(refresh)之前对其进行初始化操作。
// 可以在应用上下文启动但还未加载 bean 定义之前,对上下文进行自定义的设置和初始化操作
ApplicationContextInitializer<ConfigurableApplicationContext>,
// 这个接口允许在 Spring 应用的Environment准备好之后对其进行进一步的处理和定制。
// 可以在 Spring 应用上下文加载环境变量、系统属性和配置文件等之后,对Environment对象进行额外的配置和调整。
EnvironmentPostProcessor,
Ordered
{
// 默认顺序
public static final int DEFAULT_ORDER = 0;
// 日志
private static final Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);
// namespace分割
private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();
// apollo系统特性
private static final String[] APOLLO_SYSTEM_PROPERTIES = new String[]{
"app.id",
"apollo.cluster",
"apollo.cacheDir",
"apollo.accesskey.secret",
"apollo.meta",
"apollo.property.order.enable"
};
// 拿到一个线程安全的配置工厂对象
private final ConfigPropertySourceFactory configPropertySourceFactory = (ConfigPropertySourceFactory)SpringInjector.getInstance(ConfigPropertySourceFactory.class);
private int order = 0;
public ApolloApplicationContextInitializer() {
}
// ApolloApplicationContextInitializer在initialize方法中对应用上下文进行初始化操作
@Override
public void initialize( /**当前应用上下文**/ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
if (!(Boolean)environment.getProperty("apollo.bootstrap.enabled", Boolean.class, false)) {
logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${
{}}", context, "apollo.bootstrap.enabled");
} else {
logger.debug("Apollo bootstrap config is enabled for context {}", context);
this.initialize(environment);
}
}
// 当前累自定义的方法:initialize
protected void initialize(/**当前应用的配置环境**/ConfigurableEnvironment environment) {
// 检测是否已经有了组合属性对象(经过处理话后,会在环境对象中创建一个,没有则说明尚未完成初始化)
if (!environment.getPropertySources().contains("ApolloBootstrapPropertySources")) {
// 获取配置的apollo的namespace,默认为:application
String namespaces = environment.getProperty("apollo.bootstrap.namespaces", "application");
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
// 按照英文:“,”进行分割,拿到命名空间集合
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
// 创建一个组合属性对象
CompositePropertySource composite = new CompositePropertySource("ApolloBootstrapPropertySources");
// 拿到迭代器:准备迭代处理
Iterator i$ = namespaceList.iterator();
while(i$.hasNext()) {
// 命名空间名称
String namespace = (String)i$.next();
// 拿到具体的配置(重点逻辑:这里面有从apollo-server获取陪配置数据的逻辑)
Config config = ConfigService.getConfig(namespace);
// 往组合属性对象中丢数据
composite.addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
// 最终数据打包丢到环境对象中
environment.getPropertySources().addFirst(composite);
}
}
void initializeSystemProperty(/**当前应用的配置环境**/ConfigurableEnvironment environment) {
String[] arr$ = APOLLO_SYSTEM_PROPERTIES;
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
String propertyName = arr$[i$];
this.fillSystemPropertyFromEnvironment(environment, propertyName);
}
}
private void fillSystemPropertyFromEnvironment(/**当前应用的配置环境**/ConfigurableEnvironment environment,
String propertyName) {
if (System.getProperty(propertyName) == null) {
String propertyValue = environment.getProperty(propertyName);
if (!Strings.isNullOrEmpty(propertyValue)) {
System.setProperty(propertyName, propertyValue);
}
}
}
// 在postProcessEnvironment方法中对环境进行处理
// 执行时间节点:高于initialize( /**当前应用上下文**/ConfigurableApplicationContext context)
@Override
public void postProcessEnvironment(/**当前应用的配置环境**/ConfigurableEnvironment configurableEnvironment,
SpringApplication springApplication) {
// 初始化系统参数
this.initializeSystemProperty(configurableEnvironment);
// # 表示启用急切加载。
// 急切加载意味着在应用启动时,Apollo 客户端会尽快加载配置,而不是在首次访问配置时才加载。这可以确保应用在启动过程中尽早获取到所需的配置信息,减少潜在的延迟和不确定性。
Boolean eagerLoadEnabled = (Boolean)configurableEnvironment.getProperty("apollo.bootstrap.eagerLoad.enabled", Boolean.class, false);
if (eagerLoadEnabled) {
// # 启用 Apollo 的引导程序,这是使 Apollo 客户端在应用启动时生效的关键设置。
Boolean bootstrapEnabled = (Boolean)configurableEnvironment.getProperty("apollo.bootstrap.enabled", Boolean.class, false);
if (bootstrapEnabled) {
// 只有配置了对应的参数,才会执行初始化逻辑
this.initialize(configurableEnvironment);
}
}
}
// 通过getOrder方法返回一个执行顺序值
@Override
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}
触发顺序:
EnvironmentPostProcessor
- postProcessEnvironment(**) [ApolloApplicationContextInitializer.java]
- this.initialize(configurableEnvironment) [ApolloApplicationContextInitializer.java]
- Config config = ConfigService.getConfig(namespace) [ApolloApplicationContextInitializer.java]
- Config getConfig(String namespace) [ConfigService.java]
- getConfig(String namespace) [DefaultConfigManager.java]
-
- factory.create(namespace)
- Config create(String namespace) [DefaultConfigFactory.java]
-
- new DefaultConfig(namespace, this.createLocalConfigRepository(namespace)) :
-
-
- this.createLocalConfigRepository(namespace) :
-
-
-
-
- new LocalFileConfigRepository(*,this.createRemoteConfigRepository(namespace));
-
-
-
-
-
-
- createRemoteConfigRepository(String namespace)
-
-
-
-
-
-
-
-
- 创建RemoteConfigRepository对象,启动各种触发机制
-
-
-
-
-
-
-
-
-
-
- RemoteConfigRepository(String namespace) [RemoteConfigRepository.java]
-
-
-
-
-
-
-
-
-
-
-
-
- this.trySync();
- this.scheduleLongPollingRefresh();
-
-
-
-
-
-
-
- 最后DefaultConfig 类型包装一下
- 数据刷新到环境中
-
- composite.addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace, config));
environment.getPropertySources().addFirst(composite);
public RemoteConfigRepository(String namespace) {
// 命名空间
this.m_namespace = namespace;
//
this.m_configCache = new AtomicReference();
//
this.m_configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
this.m_httpUtil = (HttpUtil)ApolloInjector.getInstance(HttpUtil.class);
this.m_serviceLocator = (ConfigServiceLocator)ApolloInjector.getInstance(ConfigServiceLocator.class);
// 获取远程配置数据:LongPoll实时通讯交互服务,apollo动态刷新就靠它了~(定义一个服务,后面有逻辑触发)
this.remoteConfigLongPollService = (RemoteConfigLongPollService)ApolloInjector.getInstance(RemoteConfigLongPollService.class);
this.m_longPollServiceDto = new AtomicReference();
this.m_remoteMessages = new AtomicReference();
// 限流
this.m_loadConfigRateLimiter = RateLimiter.create((double)this.m_configUtil.getLoadConfigQPS());
this.m_configNeedForceRefresh = new AtomicBoolean(true);
this.m_loadConfigFailSchedulePolicy = new ExponentialSchedulePolicy(this.m_configUtil.getOnErrorRetryInterval(), this.m_configUtil.getOnErrorRetryInterval() * 8L);
this.gson = new Gson();
// 触发一次同步操作:拉取一次数据(apollo客户端首次拉取配置数据)
this.trySync();
// 刷新任务:主动拉取数据
this.schedulePeriodicRefresh();
// 实时刷新任务:启动longpolling机制
this.scheduleLongPollingRefresh();
}
private void schedulePeriodicRefresh() {
logger.debug("Schedule periodic refresh with interval: {} {}", this.m_configUtil.getRefreshInterval(), this.m_configUtil.getRefreshIntervalTimeUnit());
m_executorService.scheduleAtFixedRate(
// 定时任务逻辑
new Runnable() {
public void run() {
Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", RemoteConfigRepository.this.m_namespace));
RemoteConfigRepository.logger.debu