文章目录
- 一、启动类上加入@EnableApollo注解
- 1.1、PropertySourcesProcessor#initializePropertySources()从apollo服务端拉取配置封装成confg对象加入到environment中
- 1.1.1、ConfigService.getConfig(namespace)拉取对应namespace配置方法
- 1.1.2、factory.create创建配置工厂,并返回拉取到的远程配置
- 1.1.3、createLocalConfigRepository(namespace)创建本地配置仓库,而本地仓库的配置来源于远程配置,即:从远程拉取配置 再缓存到本地
- 1.1.4、createRemoteConfigRepository(namespace)构造远程仓库
- 1.1.5、 this.trySync()从调用远程http接口,获取远程配置
- 1.1.6、创建一个周期定时任务schedulePeriodicRefresh,调用trSync方法
- 1.1.7、创建一个长连接 获取远程实时更新scheduleLongPollingRefresh
- 1.2、流程如下
- 二、apollo客户端如何同步服务端服务修改
一、启动类上加入@EnableApollo注解
流程如下:
1.1、PropertySourcesProcessor#initializePropertySources()从apollo服务端拉取配置封装成confg对象加入到environment中
private static final String APOLLO_PROPERTY_SOURCE_NAME = "ApolloPropertySources";
protected void initializePropertySources() {
if (environment.getPropertySources().contains(APOLLO_PROPERTY_SOURCE_NAME)) {
//已经加载过了,返回
return;
}
CompositePropertySource composite = new CompositePropertySource(APOLLO_PROPERTY_SOURCE_NAME);
//sort by order asc
ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
Iterator<Integer> iterator = orders.iterator();
//遍历每个命名空间
while (iterator.hasNext()) {
int order = iterator.next();
for (String namespace : NAMESPACE_NAMES.get(order)) {
//获取命名空间的配置对象--》从远程服务获取
Config config = ConfigService.getConfig(namespace);
composite.addPropertySource(new ConfigPropertySource(namespace, config));
}
}
//加到spring 环境对象中,后面注入的时候 就可以从environment对象中获取apollo配置的值
environment.getPropertySources().addFirst(composite);
}
1.1.1、ConfigService.getConfig(namespace)拉取对应namespace配置方法
public Config getConfig(String namespace) {
Config config = m_configs.get(namespace);
if (config == null) {
synchronized (this) {
config = m_configs.get(namespace);
if (config == null) {
//获取配置工厂对象,反射创建DefaultConfigFactory对象返回
ConfigFactory factory = m_factoryManager.getFactory(namespace);
//调用create方法,返回配置对象
config = factory.create(namespace);
m_configs.put(namespace, config);
}
}
}
return config;
}
1.1.2、factory.create创建配置工厂,并返回拉取到的远程配置
@Override
public Config create(String namespace) {
DefaultConfig defaultConfig =
//createLocalConfigRepository(namespace)创建本地配置仓库,apollo会从远程拉取配置后,缓存到本地
new DefaultConfig(namespace, createLocalConfigRepository(namespace));
return defaultConfig;
}
1.1.3、createLocalConfigRepository(namespace)创建本地配置仓库,而本地仓库的配置来源于远程配置,即:从远程拉取配置 再缓存到本地
createLocalConfigRepository(namespace)创建本地配置仓库,而这个本地仓库的配置来源,来源于远程,apollo会从远程拉取配置后,缓存到本地。有点类似于 装饰器模式。 本地配置仓库 装饰了远程配置仓库
LocalFileConfigRepository createLocalConfigRepository(String namespace) {
//根据应用程序配置的env环境 判断是否本地模式,一般都不是本地模式
//本地模式--》从固定目录下读取配置文件构造本地配置仓库缓存
//非本模式---》从远程服务读取配置,然后构造本地仓库缓存
//m_configUtil.isInLocalMode()放通过spi构造ProviderManager (用于管理provider的对象),这个对象构造方法中初始化了3种 配置env环境的proiver,1、从//META-INF/app.properties文件读取2、从/opt/settings/server.properties文件读取,3、从网络读取
//默认从/opt/settings/server.properties文件中读取。这个方法又分优先级 jvm property > 操作系统变量--> server.properties配置文件
if (m_configUtil.isInLocalMode()) {
logger.warn(
"==== Apollo is in local mode! Won't pull configs from remote server for namespace {} ! ====",
namespace);
return new LocalFileConfigRepository(namespace);
}
return new LocalFileConfigRepository(namespace, createRemoteConfigRepository(namespace));
}
1.1.4、createRemoteConfigRepository(namespace)构造远程仓库
RemoteConfigRepository createRemoteConfigRepository(String namespace) {
//查看它的构造方法
return new RemoteConfigRepository(namespace);
}
new RemoteConfigRepository(namespace);
public RemoteConfigRepository(String namespace) {
m_namespace = namespace;
m_configCache = new AtomicReference<>();
m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
m_httpUtil = ApolloInjector.getInstance(HttpUtil.class);
m_serviceLocator = ApolloInjector.getInstance(ConfigServiceLocator.class);
remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class);
m_longPollServiceDto = new AtomicReference<>();
m_loadConfigRateLimiter = RateLimiter.create(m_configUtil.getLoadConfigQPS());
//从调用远程http接口,获取远程配置
this.trySync();
//创建一个周期定时任务,调用trSync方法
this.schedulePeriodicRefresh();
//while循环中,创建一个长连接 获取远程是否有更新,如果在超时时间范围内有返回,说明配置文件有更新,那么调用trySync方法。如果超时 那么while循环再次发起这个长连接
this.scheduleLongPollingRefresh();
}
1.1.5、 this.trySync()从调用远程http接口,获取远程配置
protected synchronized void sync() {
Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "syncRemoteConfig");
try {
//获取本地版本
ApolloConfig previous = m_configCache.get();
//从远程获取最新版本
ApolloConfig current = loadApolloConfig();
//如果不同,那么触发更新
if (previous != current) {
logger.debug("Remote Config refreshed!");
m_configCache.set(current);
this.fireRepositoryChange(m_namespace, this.getConfig());
}
if (current != null) {
Tracer.logEvent(String.format("Apollo.Client.Configs.%s", current.getNamespaceName()),
current.getReleaseKey());
}
transaction.setStatus(Transaction.SUCCESS);
} catch (Throwable ex) {
transaction.setStatus(ex);
throw ex;
} finally {
transaction.complete();
}
}
1.1.6、创建一个周期定时任务schedulePeriodicRefresh,调用trSync方法
private void schedulePeriodicRefresh() {
m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit());
m_executorService.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
//每隔一个刷新时间调用 检测有没有同步
trySync();
}
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
m_configUtil.getRefreshIntervalTimeUnit());
}
1.1.7、创建一个长连接 获取远程实时更新scheduleLongPollingRefresh
m_longPollingService.submit(new Runnable() {
@Override
public void run() {
//发起一个长链接 监听更新
doLongPollingRefresh(appId, cluster, dataCenter, secret);
}
});
private void doLongPollingRefresh(String appId, String cluster, String dataCenter, String secret) {
while (!m_longPollingStopped.get() && !Thread.currentThread().isInterrupted()) {
url =assembleLongPollRefreshUrl(lastServiceDto.getHomepageUrl(), appId, cluster, dataCenter,
m_notifications);
final HttpResponse<List<ApolloConfigNotification>> response =
m_httpUtil.doGet(request, m_responseType);
//如果200表示的更新,那么通知
if (response.getStatusCode() == 200 && response.getBody() != null) {
updateNotifications(response.getBody());
updateRemoteNotifications(response.getBody());
transaction.addData("Result", response.getBody().toString());
notify(lastServiceDto, response.getBody());
}
//304表示超时,没有更新,继续上面的while,再发起一个长链接
if (response.getStatusCode() == 304 && random.nextBoolean()) {
lastServiceDto = null;
}
}
}
1.2、流程如下
二、apollo客户端如何同步服务端服务修改
详情可查看,apollo配置中心之-如何启动源码及Config Service 通知客户端配置变化源码解析----客户端监听