![JAR search and dependency download from the Maven repository](/logo.png)
com.github.javaclub.configcenter.client.DefaultConfigCenterClient Maven / Gradle / Ivy
package com.github.javaclub.configcenter.client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.github.javaclub.configcenter.client.domain.CfgVO;
import com.github.javaclub.configcenter.client.util.DESCoder;
import com.github.javaclub.configcenter.client.util.HttpHelper;
import com.github.javaclub.configcenter.client.util.PropUtil;
import com.github.javaclub.configcenter.client.util.PropUtil.Configuration;
import com.github.javaclub.configcenter.client.util.Utils;
public class DefaultConfigCenterClient implements ConfigCenterClient {
private static final Logger logger = LoggerFactory.getLogger(DefaultConfigCenterClient.class);
private static String endpoint; // ip:port 如:127.0.0.1:7001
private static ConcurrentMap appMap = new ConcurrentHashMap();
private static ConcurrentMap> cfg = new ConcurrentHashMap>();
private static ExecutorService exector = Executors.newFixedThreadPool(5);
private static AtomicBoolean inited = new AtomicBoolean(false);
private static String env;
public static final String JAR_GROUP_ID = "com.github.javaclub";
public static final String JAR_ARTIFACT_ID = "configcenter-client";
/**
* 需要在实际项目环境 classpath:server.properties 文件种定义,如:
*
* configserver.address=192.168.31.216:7001;192.168.31.60:7001
*
*/
private static final String CONFIG_SERVER_ADDRESS = "configserver.address";
public DefaultConfigCenterClient() {
String serverIps = this.ensureReady();
String[] ipArray = StringUtils.split(serverIps, ";");
for (String ipAndPort : ipArray) {
if(StringUtils.isBlank(ipAndPort)) {
continue;
}
String testUrl = "http://" + ipAndPort.trim() + "/configcenter/webStatus?timestamp=" + System.currentTimeMillis();
try {
String resp = HttpHelper.get(testUrl);
if(!StringUtils.equals("success", resp)) {
continue;
}
} catch (Exception e) {
logger.error("Test configcenter server address => " + ipAndPort, e);
}
DefaultConfigCenterClient.endpoint = ipAndPort.trim();
break;
}
if(Utils.isBlank(getEndpoint())) {
throw new RuntimeException("No available configcenter server address in => [" + serverIps + "]");
}
}
String ensureReady() {
Configuration conf = null;
try {
conf = PropUtil.getConfiguration();
} catch (Throwable e) {
throw e;
}
if(null == conf) {
throw new RuntimeException("The config file => [server.properties] not be found in classpath");
}
if(Utils.isBlank(conf.getValue(CONFIG_SERVER_ADDRESS))) {
throw new RuntimeException("KEY:" + CONFIG_SERVER_ADDRESS + " should be set in file => [classpath:server.properties]");
}
try {
env = conf.getValue("env");
} catch (Exception e) {
}
return conf.getValue(CONFIG_SERVER_ADDRESS);
}
public void init(int appid, String appkey) {
if (inited.compareAndSet(false, true)) {
ConfigServer.getInstance().setEndPoint(endpoint);
ConfigServer.getInstance().setEnv(env);
ConfigServer.getInstance().setAppid(String.valueOf(appid));
ConfigServer.getInstance().setAppkey(appkey);
ConfigServer.getInstance().init();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000L);
if (!appMap.isEmpty()) {
Map > queryParam = new HashMap>();
for (int appid : appMap.keySet()) {
AppCfg appCfg = appMap.get(appid);
queryParam.put(appCfg.appid, new HashMap());
synchronized (appCfg.lock) {
for (String configkey : appCfg.configKeyList) {
queryParam.get(appid).put(configkey, "0");
if (cfg.get(appid) != null && cfg.get(appid).get(configkey) != null) {
queryParam.get(appid).put(configkey, cfg.get(appid).get(configkey).timestamp);
}
}
}
}
if (!queryParam.isEmpty()) {
if (polling(queryParam)) { // 配置有更新
for (int appid : cfg.keySet()) { // 保存文件快照
ConfigLocalSave.getInstance().snapshot(appid, appMap.get(appid).getAppkey(),
cfg.get(appid).values());
}
} else {
for (int appid : cfg.keySet()) {
// 本地无配置数据时,保存
if (null == ConfigLocalSave.getInstance().readConfigFromFile(appid,
appMap.get(appid).getAppkey())) {
ConfigLocalSave.getInstance().snapshot(appid, appMap.get(appid).getAppkey(),
cfg.get(appid).values());
}
}
}
}
}
} catch (Throwable t) {
logger.error("", t);
}
}
}
});
t.setName("config-center-client");
t.setDaemon(true);
t.start();
}
}
// 查询配置是否变更
private static boolean polling(Map > param) {
StringBuilder sb = new StringBuilder();
sb.append("http://");
sb.append(ConfigServer.getInstance().getOneServer());
sb.append("/configcenter/item/query/batch?clientVer=" + getClientVersion());
boolean flag = false;
try {
final
Map postBody = new HashMap();
for (int appid : param.keySet()) {
postBody.put(appid, DESCoder.encrypt(JSONObject.toJSONString(param.get(appid)), appMap.get(appid).appkey));
}
String resp = HttpHelper.post(sb.toString(), JSONObject.toJSONString(postBody));
if (StringUtils.isNotBlank(resp)) {
JSONObject result = JSONObject.parseObject(resp);
if (result.getShort("code") == 0) {
@SuppressWarnings("unchecked")
Map map = JSONObject.parseObject(result.getString("result"), Map.class);
if (map != null && !map.isEmpty()) {
for (final int appid : map.keySet()) {
String str = DESCoder.decrpty(map.get(appid), appMap.get(appid).appkey);
@SuppressWarnings("unchecked")
final Map cfgMap = JSONObject.parseObject(str, Map.class);
if (cfgMap != null && !cfgMap.isEmpty()) {
cfg.putIfAbsent(appid, new HashMap());
for (String configkey : cfgMap.keySet()) {
JSONObject jSONObject = cfgMap.get(configkey);
CfgVO cfgVO = new CfgVO(jSONObject.getString("configkey"), jSONObject.getString("configvalue"),
jSONObject.getString("timestamp"));
cfg.get(appid).put(configkey, cfgVO);
}
flag = true;
for (final String configkey : cfgMap.keySet()) {
synchronized (appMap.get(appid).lock) {
if (!appMap.get(appid).listeners.get(configkey).isEmpty()) {
for (final ConfigListener configListener : appMap.get(appid).listeners.get(configkey)) {
exector.submit(new Runnable() {
@Override
public void run() {
try {
JSONObject jSONObject = cfgMap.get(configkey);
CfgVO cfgVO = new CfgVO(jSONObject.getString("configkey"), jSONObject
.getString("configvalue"), jSONObject.getString("timestamp"));
configListener.update(cfgVO.getConfigvalue()); // 触发监听器
report(false, appid, appMap.get(appid).appkey, configkey, cfgVO.getConfigvalue());
} catch (Exception e) {
logger.error("", e);
}
}
});
}
}
}
}
}
}
}
} else {
logger.error("failed to getConfig:" + resp);
}
}
} catch (Exception e) {
logger.error("", e);
}
return flag;
}
@Override
public String getConfig(int appid, String appkey, String configkey, ConfigListener configListener) {
if (!inited.get()) {
init(appid,appkey);
}
appMap.putIfAbsent(appid, new AppCfg());
AppCfg appCfg = appMap.get(appid);
appCfg.setAppid(appid);
appCfg.setAppkey(appkey);
String value = null;
try {
value = queryConfig(appid, appkey, configkey);
} catch (Exception e) {
logger.error("", e);
} finally {
if(value == null) {
Map map = ConfigLocalSave.getInstance().get(appid, appkey, configkey);
if (map != null) {
value = map.get("value");
String timestamp = map.get("timestamp");
CfgVO cfgVO = new CfgVO(configkey, value, timestamp);
cfg.putIfAbsent(appid, new HashMap());
cfg.get(appid).put(configkey, cfgVO);
logger.warn("from local cfg:{},{},{}",appid,configkey,value);
}
}
appCfg.addConfigKey(configkey, configListener); // 注册配置项及监听器
if(value != null) {
report(true, appid, appkey, configkey, value);
} else {
throw new ConfigException(String.format("failed to get config: appid[%s],configkey[%s]", appid, configkey));
}
}
return value;
}
private String queryConfig(int appid, String appkey, String configkey) throws ConfigException {
try {
String resp = null;
configkey = configkey.trim();
appkey = appkey.trim();
try {
resp = doQuery(appid, appkey, configkey);
} catch (Exception e) {
}
if(StringUtils.isBlank(resp)){ // retry
Thread.sleep(1000l);
resp = doQuery(appid, appkey, configkey);
}
if (StringUtils.isNotBlank(resp)) {
JSONObject result = JSONObject.parseObject(resp);
if (result.getShort("code") == 0) {
if (StringUtils.isNotBlank(result.getString("result"))) {
String v = DESCoder.decrpty(result.getString("result"), appkey);
if (StringUtils.isNotBlank(v)) {
@SuppressWarnings("unchecked")
Map map = JSONObject.parseObject(v, Map.class);
String value = map.get("value");
String timestamp = map.get("timestamp");
CfgVO cfgVO = new CfgVO(configkey, value, timestamp);
cfg.putIfAbsent(appid, new HashMap());
cfg.get(appid).put(configkey, cfgVO);
return value;
}
}
} else {
logger.error("failed to getConfig:" + resp);
throw new ConfigException(resp);
}
}
} catch (Exception e) {
throw new ConfigException(e.getMessage());
}
return null;
}
private String doQuery(int appid, String appkey, String configkey) throws Exception {
final StringBuilder sb = new StringBuilder();
sb.append("http://");
sb.append(ConfigServer.getInstance().getOneServer());
sb.append("/configcenter/item/query?clientVer=" + getClientVersion());
sb.append("&appid=" + appid);
sb.append("&key=" + configkey);
Future future = exector.submit(new Callable() {
@Override
public String call() throws Exception {
String resp = HttpHelper.get(sb.toString());
return resp;
}
});
return future.get(3, TimeUnit.SECONDS);
}
private static void report(boolean asyn, int appid, String appkey, String configkey, String configValue) {
int retry = 2;
while (retry-- > 0) {
final StringBuilder sb = new StringBuilder();
sb.append("http://");
sb.append(ConfigServer.getInstance().getOneServer());
sb.append("/configcenter/report?clientVer=" + getClientVersion());
sb.append("&appid=" + appid);
sb.append("&configKey=" + configkey);
try {
final String text = DESCoder.encrypt(configValue, appkey);
Future future = exector.submit(new Callable() {
@Override
public String call() throws Exception {
return HttpHelper.post(sb.toString(), text);
}
});
if (!asyn) {
if ("true".equals(future.get(3, TimeUnit.SECONDS))) {
return;
}
}else{
break;
}
} catch (Exception e) {
logger.error("", e);
}
}
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
DefaultConfigCenterClient.endpoint = endpoint;
}
public class AppCfg {
public int appid;
public String appkey;
public List configKeyList = new ArrayList();
public Map> listeners = new HashMap>();
public Object lock = new Object();
public void addConfigKey(String configkey, ConfigListener configListener) {
synchronized (lock) {
if (!configKeyList.contains(configkey)) {
configKeyList.add(configkey);
}
if (configListener != null) {
if (listeners.get(configkey) == null) {
listeners.put(configkey, new ArrayList());
}
if (!listeners.get(configkey).contains(configListener)) {
listeners.get(configkey).add(configListener);
}
}
}
}
public int getAppid() {
return appid;
}
public void setAppid(int appid) {
this.appid = appid;
}
public String getAppkey() {
return appkey;
}
public void setAppkey(String appkey) {
this.appkey = appkey;
}
@Override
public String toString() {
return "AppCfg [appid=" + appid + ", appkey=" + appkey + ", configKeyList=" + configKeyList + ", listeners=" + listeners
+ ", lock=" + lock + "]";
}
}
@Override
public boolean setConfig(int appid, String appkey, String configKey, String configValue) throws ConfigException {
try {
if (!inited.get()) {
init(appid,appkey);
}
final StringBuilder sb = new StringBuilder();
sb.append("http://");
sb.append(ConfigServer.getInstance().getOneServer());
sb.append("/configcenter/item/update?clientVer=" + getClientVersion());
sb.append("&appid=" + appid);
Map map = new HashMap();
map.put("key", configKey);
map.put("value", configValue);
final String text = DESCoder.encrypt(JSONObject.toJSONString(map), appkey);
Future future = exector.submit(new Callable() {
@Override
public String call() throws Exception {
String resp = HttpHelper.post(sb.toString(), text);
return resp;
}
});
return "success".equals(future.get(3, TimeUnit.SECONDS));
} catch (Exception e) {
throw new ConfigException(e);
}
}
/**
* 取当前客户端在使用的版本
*
* @return configcenter-client版本号
*/
public static String getClientVersion() {
return Utils.getConfigClientVer();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy