v1.0.0版本

This commit is contained in:
eson 2022-06-19 23:29:30 +08:00
parent f285fffe30
commit 8295e36210
3 changed files with 162 additions and 100 deletions

View File

@ -24,193 +24,219 @@ import com.alibaba.nacos.api.exception.NacosException;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
* description nacos配置. * description nacos配置.
* *
* @author eson * @author eson
*2022年6月13日-17:08:46 * 2022年6月13日-17:08:46
*/ */
@Slf4j @Slf4j
@Getter @Getter
@Setter @Setter
public class Config { public class Config {
/** 加载的配置文件名, 在{@docRoot}/resources下 */
public static String DEFAULT_CONFIT_FILE = "application.properties"; public static String DEFAULT_CONFIT_FILE = "application.properties";
/** properties 的配置key. nacos地址 */
public static String DEFAULT_CONFIG_ADDR = "yuandian.dataflow.config.nacos.server.addr"; public static String DEFAULT_CONFIG_ADDR = "yuandian.dataflow.config.nacos.server.addr";
// public static String DEFAULT_CONFIG_DATAID = "yuandian.dataflow.config.nacos.dataid";
// public static String DEFAULT_CONFIG_GROUP = "yuandian.dataflow.config.nacos.group";+
// 默认 // 默认
public static String DEFAULT_GROUP_DATAID = "yuandian.dataflow"; public static String DEFAULT_GROUP_DATAID = "yuandian.dataflow";
// 所有生成的nacos客户端 // 所有生成的nacos客户端
private static HashMap<String,Config> configDict = new HashMap<>(); private static HashMap<String, Config> configDict = new HashMap<>();
// 配置的所有值主类 // 配置的所有值主类
public Map<String,Object> data; public Map<String, Object> data;
// nacos地址 // nacos地址
public String serverAddr ; public String serverAddr;
// nacos dataId // nacos dataId
public String dataId ; public String dataId;
// nacos group // nacos group
public String group ; public String group;
// 线程安全配置锁 // 线程安全配置锁
private Lock datalock; private Lock datalock;
// nacos 客户端类 // nacos 客户端类
private ConfigService configService; private ConfigService configService;
private Config(String GroupAndDataId) throws Exception {
private Config(String GroupAndDataId) throws Exception {
String[] gad = GroupAndDataId.split("\\."); String[] gad = GroupAndDataId.split("\\.");
if(gad.length != 2) { if (gad.length != 2) {
throw new Exception("Group 或者 DataId 不能存在 '.' 的命令"); throw new Exception("Group 或者 DataId 不能存在 '.' 的命令");
} }
this.group = gad[0] + ENV_TEST; this.group = gad[0] + ENV_TEST;
this.dataId = gad[1] + ENV_TEST; this.dataId = gad[1] + ENV_TEST;
connect(); connect();
} }
/** /**
* 连接nacos * 连接nacos
*
* @throws IOException * @throws IOException
* @throws NacosException * @throws NacosException
*/ */
private void connect() throws IOException, NacosException { private void connect() throws IOException, NacosException {
if(configService != null) { if (configService != null) {
configService.shutDown(); configService.shutDown();
configService = null; configService = null;
}
// 获取 app
Properties prop = new Properties();
prop.load(Config.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIT_FILE));
serverAddr = trim(prop.getProperty(DEFAULT_CONFIG_ADDR + ENV_TEST), "\" '");
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(dataId, group, 5000);
Yaml yaml = new Yaml();
data = yaml.load(content);
log.info(content);
datalock = new ReentrantLock();
// 监听 配置更新事件
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.debug("recieve:" + configInfo);
try {
datalock.lock();
data = (Map<String, Object>) new Yaml().load(configInfo);
log.debug("{}", data);
} finally {
datalock.unlock();
}
} }
// 获取 app
Properties prop = new Properties(); @Override
prop.load(Config.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIT_FILE)); public Executor getExecutor() {
return null;
serverAddr = prop.getProperty(DEFAULT_CONFIG_ADDR + ENV_TEST).trim(); }
// dataId = prop.getProperty(DEFAULT_CONFIG_DATAID).trim(); });
// group = prop.getProperty(DEFAULT_CONFIG_GROUP).trim();
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(dataId, group, 5000);
Yaml yaml = new Yaml();
data = yaml.load(content);
log.info(content);
datalock = new ReentrantLock();
// 监听 配置更新事件
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.debug("recieve:" + configInfo);
try {
datalock.lock();
data = (Map<String, Object>)new Yaml().load(configInfo);
log.debug("{}",data);
} finally {
datalock.unlock();
}
}
@Override
public Executor getExecutor() {
return null;
}
});
} }
/** /**
* 根据多个key获取yaml的值 keys 路径 * 根据多个key获取yaml的值 keys 路径
*
* @param keys 获取的key值 * @param keys 获取的key值
* @return * @return
*/ */
public Object get(String ...keys) { public Object get(String... keys) {
var cur = data; var cur = data;
for(var i = 0; i < keys.length - 1;i++ ) { for (var i = 0; i < keys.length - 1; i++) {
var key = keys[i]; var key = keys[i];
cur = (Map<String, Object>) cur.get(key); cur = (Map<String, Object>) cur.get(key);
} }
return cur.get(keys[keys.length - 1]); return cur.get(keys[keys.length - 1]);
} }
/** /**
* *
* 用于定位keys的路径后的操作. 创建keys后赋值. 如果存在keys, 可以直接赋值, 不存在则直接报错 * 用于定位keys的路径后的操作. 创建keys后赋值. 如果存在keys, 可以直接赋值, 不存在则直接报错
* *
* @author eson * @author eson
*2022年6月15日-下午12:06:37 * 2022年6月15日-下午12:06:37
*/ */
public class Operator { public class Operator {
Config config; Config config;
String[] keys; String[] keys;
Operator(Config config, String[] keys) { Operator(Config config, String[] keys) {
this.config = config; this.config = config;
this.keys = keys; this.keys = keys;
} }
/** /**
* 创建seek的key * 创建seek的key
* @return *
* @return 返回自身
*/ */
public Operator createKeys() { public Operator createKeys() {
var cur = config.data; var cur = config.data;
for(var i = 0; i < keys.length;i++ ) { for (var i = 0;;) {
var key = keys[i]; var key = keys[i];
var vobj = cur.get(key); var vobj = cur.get(key);
if (vobj == null) { if (vobj == null) {
vobj = new LinkedHashMap<>(); vobj = new LinkedHashMap<>();
cur.put(key, vobj); cur.put(key, vobj);
} }
i++;
if (i >= keys.length) {
break;
}
cur = (Map<String, Object>) vobj; cur = (Map<String, Object>) vobj;
} }
return this; return this;
} }
/** /**
* 定位后赋值 * 定位后赋值
* @param value *
* @param value 赋值
*/ */
public void set(Object value) { public void set(Object value) {
var cur = config.data; var cur = config.data;
for(var i = 0; i < keys.length - 1;i++ ) { for (var i = 0; i < keys.length - 1; i++) {
var key = keys[i]; var key = keys[i];
cur = (Map<String, Object>) cur.get(key); cur = (Map<String, Object>) cur.get(key);
} }
cur.put(keys[keys.length - 1], value); cur.put(keys[keys.length - 1], value);
} }
} }
/** /**
* 定位. eg. seek("key1", "key2") * 定位. eg. seek("key1", "key2")
*
* @param keys * @param keys
* @return * @return 返回自身
*/ */
public Operator seek(String ...keys) { public Operator seek(String... keys) {
return new Operator(this, keys); return new Operator(this, keys);
} }
/** /**
* 删除 key的值. 类型map操作. keys是一个路径 remove("a","b") --> {"a": {"b": 1}} 删除b * 删除 key的值. 类型map操作. keys是一个路径 remove("a","b") --> {"a": {"b": 1}} 删除b
*
* @param map
* @param keys * @param keys
* @return * @return
*/ */
public Object remove(String ...keys) { public Object remove(String... keys) {
var cur = data; var cur = data;
for(var i = 0; i < keys.length - 1;i++ ) { for (var i = 0; i < keys.length - 1; i++) {
var key = keys[i]; var key = keys[i];
cur = (Map<String, Object>) cur.get(key); cur = (Map<String, Object>) cur.get(key);
} }
return cur.remove(keys[keys.length - 1]); return cur.remove(keys[keys.length - 1]);
} }
/** /**
* 更新配置 * 更新配置
*
* @return 返回是否发布成功. * @return 返回是否发布成功.
* @throws NacosException * @throws NacosException
*/ */
public Boolean update() throws NacosException { public Boolean update() throws NacosException {
return configService.publishConfig(dataId, group,new Yaml().dumpAsMap(data)); return configService.publishConfig(dataId, group, new Yaml().dumpAsMap(data));
} }
public static String ENV_TEST = ""; public static String ENV_TEST = "";
/** /**
* 统一使用配置的入口函数 线程安全 * 统一使用配置的入口函数 线程安全
*
* @param GroupAndDataID 使用配置的标签 eg."group.dataId" * @param GroupAndDataID 使用配置的标签 eg."group.dataId"
* @param execute 匿名函数 * @param execute 匿名函数
* @return 函数返回的值, 如果不需要直接返回null * @return 函数返回的值, 如果不需要直接返回null
* @throws Exception * @throws Exception
*/ */
public static Object UseConfig(String GroupAndDataID, Function<Config, Object> execute) throws Exception { public static Object UseConfig(String GroupAndDataID, Function<Config, Object> execute) throws Exception {
log.info(GroupAndDataID); log.info(GroupAndDataID);
Config cnf; Config cnf;
synchronized(configDict) { synchronized (configDict) {
cnf = configDict.get(GroupAndDataID); cnf = configDict.get(GroupAndDataID);
if(cnf == null) { if (cnf == null) {
cnf = new Config(GroupAndDataID); cnf = new Config(GroupAndDataID);
configDict.put(GroupAndDataID, cnf); configDict.put(GroupAndDataID, cnf);
} }
@ -218,46 +244,61 @@ public class Config {
try { try {
cnf.datalock.lock(); cnf.datalock.lock();
var res = execute.apply(cnf); var res = execute.apply(cnf);
return res; return res;
} catch (Exception e) { } catch (Exception e) {
throw e; throw e;
} finally { } finally {
cnf.datalock.unlock(); cnf.datalock.unlock();
} }
} }
/**
* 统一使用配置的入口函数 线程安全 /**
* @param execute 统一使用配置的入口匿名方法 * 统一使用配置的入口函数 线程安全
* @return 函数返回的值, 如果不需要直接返回null *
* @param execute 统一使用配置的入口匿名方法
* @return 函数返回的值, 如果不需要直接返回null
* @throws Exception * @throws Exception
*/ */
public static Object UseConfig(Function<Config, Object> execute) throws Exception { public static Object UseConfig(Function<Config, Object> execute) throws Exception {
return UseConfig(DEFAULT_GROUP_DATAID, execute); return UseConfig(DEFAULT_GROUP_DATAID, execute);
} }
private static String Trim(String o, String mychars){
if(o == null) { /**
* 函数移除字符串两侧 预定义字符
*
* @param trimedstr 需要修改的字符串
* @param mychars 定义修改的字符集合
* @return 修正后的字符串.
*/
private static String trim(String trimedstr, String mychars) {
if (trimedstr == null) {
return null; return null;
} else if (o.length() == 0) { } else if (trimedstr.length() == 0) {
return o; return trimedstr;
} }
var buf = o.toCharArray();
var buf = trimedstr.toCharArray();
var chars = mychars.toCharArray(); var chars = mychars.toCharArray();
var start = 0; var start = 0;
for( ; start < buf.length; start++) {
for(var c: chars){ TOPLOOP1: for (; start < buf.length; start++) {
if(buf[start] != c) { for (var c : chars) {
break; if (buf[start] == c) {
} continue TOPLOOP1;
}
} }
break;
} }
var end = buf.length;
for( ; end >= 0; end--) { var end = buf.length - 1;
for(var c: chars){ TOPLOOP2: for (; end >= 0; end--) {
if(buf[start] != c) { for (var c : chars) {
break; if (buf[end] == c) {
} continue TOPLOOP2;
}
} }
break;
} }
return null; return trimedstr.substring(start, end + 1);
} }
} }

View File

@ -1,6 +1,6 @@
server.port=3440 server.port=3440
yuandian.dataflow.config.nacos.server.addr="192.168.1.113:8848" yuandian.dataflow.config.nacos.server.addr=localhost:8848
yuandian.dataflow.config.nacos.server.addr-test="192.168.1.113:8848" yuandian.dataflow.config.nacos.server.addr-test=localhost:8848

View File

@ -27,6 +27,9 @@ public class ConfigTest {
Assertions.assertEquals(cnf.get("key1", "key2"), "key_path"); Assertions.assertEquals(cnf.get("key1", "key2"), "key_path");
Instant now = Instant.now(); Instant now = Instant.now();
cnf.data.put("use_config", now.toString()); cnf.data.put("use_config", now.toString());
try { try {
log.info("{}",cnf.update()); log.info("{}",cnf.update());
} catch (NacosException e) { } catch (NacosException e) {
@ -35,6 +38,24 @@ public class ConfigTest {
return null; return null;
}); });
} }
@Test
@Order(1)
void testUseConfigUpdate() throws Exception {
Config.ENV_TEST = "-test";
Config.UseConfig((cnf) -> {
cnf.seek("create1","create2", "create3").createKeys().set("create_for_remove");;
try {
log.info("{}",cnf.update());
} catch (NacosException e) {
e.printStackTrace();
}
return null;
});
}
@Test @Test
@Order(2) @Order(2)
void testRemove() throws Exception { void testRemove() throws Exception {