com.ctrip.framework.apollo.internals.ConfigServiceLocator Maven / Gradle / Ivy
The newest version!
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.ServiceNameConsts;
import com.ctrip.framework.foundation.Foundation;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ctrip.framework.apollo.build.ApolloInjector;
import com.ctrip.framework.apollo.core.dto.ServiceDTO;
import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.ctrip.framework.apollo.exceptions.ApolloConfigException;
import com.ctrip.framework.apollo.tracer.Tracer;
import com.ctrip.framework.apollo.tracer.spi.Transaction;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.ctrip.framework.apollo.util.ExceptionUtil;
import com.ctrip.framework.apollo.util.http.HttpRequest;
import com.ctrip.framework.apollo.util.http.HttpResponse;
import com.ctrip.framework.apollo.util.http.HttpUtil;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.google.gson.reflect.TypeToken;
public class ConfigServiceLocator {
private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
private HttpUtil m_httpUtil;
private ConfigUtil m_configUtil;
private AtomicReference> m_configServices;
private Type m_responseType;
private ScheduledExecutorService m_executorService;
private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
/**
* Create a config service locator.
*/
public ConfigServiceLocator() {
List initial = Lists.newArrayList();
m_configServices = new AtomicReference<>(initial);
m_responseType = new TypeToken>() {
}.getType();
m_httpUtil = ApolloInjector.getInstance(HttpUtil.class);
m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
this.m_executorService = Executors.newScheduledThreadPool(1,
ApolloThreadFactory.create("ConfigServiceLocator", true));
initConfigServices();
}
private void initConfigServices() {
// get from run time configurations
List customizedConfigServices = getCustomizedConfigService();
if (customizedConfigServices != null) {
setConfigServices(customizedConfigServices);
return;
}
// update from meta service
this.tryUpdateConfigServices();
this.schedulePeriodicRefresh();
}
private List getCustomizedConfigService() {
// 1. Get from System Property
String configServices = System.getProperty("apollo.configService");
if (Strings.isNullOrEmpty(configServices)) {
// 2. Get from OS environment variable
configServices = System.getenv("APOLLO_CONFIGSERVICE");
}
if (Strings.isNullOrEmpty(configServices)) {
// 3. Get from server.properties
configServices = Foundation.server().getProperty("apollo.configService", null);
}
if (Strings.isNullOrEmpty(configServices)) {
return null;
}
logger.warn("Located config services from apollo.configService configuration: {}, will not refresh config services from remote meta service!", configServices);
// mock service dto list
String[] configServiceUrls = configServices.split(",");
List serviceDTOS = Lists.newArrayList();
for (String configServiceUrl : configServiceUrls) {
configServiceUrl = configServiceUrl.trim();
ServiceDTO serviceDTO = new ServiceDTO();
serviceDTO.setHomepageUrl(configServiceUrl);
serviceDTO.setAppName(ServiceNameConsts.APOLLO_CONFIGSERVICE);
serviceDTO.setInstanceId(configServiceUrl);
serviceDTOS.add(serviceDTO);
}
return serviceDTOS;
}
/**
* Get the config service info from remote meta server.
*
* @return the services dto
*/
public List getConfigServices() {
if (m_configServices.get().isEmpty()) {
updateConfigServices();
}
return m_configServices.get();
}
private boolean tryUpdateConfigServices() {
try {
updateConfigServices();
return true;
} catch (Throwable ex) {
//ignore
}
return false;
}
private void schedulePeriodicRefresh() {
this.m_executorService.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
logger.debug("refresh config services");
Tracer.logEvent("Apollo.MetaService", "periodicRefresh");
tryUpdateConfigServices();
}
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
m_configUtil.getRefreshIntervalTimeUnit());
}
private synchronized void updateConfigServices() {
String url = assembleMetaServiceUrl();
HttpRequest request = new HttpRequest(url);
int maxRetries = 2;
Throwable exception = null;
for (int i = 0; i < maxRetries; i++) {
Transaction transaction = Tracer.newTransaction("Apollo.MetaService", "getConfigService");
transaction.addData("Url", url);
try {
HttpResponse> response = m_httpUtil.doGet(request, m_responseType);
transaction.setStatus(Transaction.SUCCESS);
List services = response.getBody();
if (services == null || services.isEmpty()) {
logConfigService("Empty response!");
continue;
}
setConfigServices(services);
return;
} catch (Throwable ex) {
Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
transaction.setStatus(ex);
exception = ex;
} finally {
transaction.complete();
}
try {
m_configUtil.getOnErrorRetryIntervalTimeUnit().sleep(m_configUtil.getOnErrorRetryInterval());
} catch (InterruptedException ex) {
//ignore
}
}
throw new ApolloConfigException(
String.format("Get config services failed from %s", url), exception);
}
private void setConfigServices(List services) {
m_configServices.set(services);
logConfigServices(services);
}
private String assembleMetaServiceUrl() {
String domainName = m_configUtil.getMetaServerDomainName();
String appId = m_configUtil.getAppId();
String localIp = m_configUtil.getLocalIp();
Map queryParams = Maps.newHashMap();
queryParams.put("appId", queryParamEscaper.escape(appId));
if (!Strings.isNullOrEmpty(localIp)) {
queryParams.put("ip", queryParamEscaper.escape(localIp));
}
return domainName + "/services/config?" + MAP_JOINER.join(queryParams);
}
private void logConfigServices(List serviceDtos) {
for (ServiceDTO serviceDto : serviceDtos) {
logConfigService(serviceDto.getHomepageUrl());
}
}
private void logConfigService(String serviceUrl) {
Tracer.logEvent("Apollo.Config.Services", serviceUrl);
}
}