From f285fffe30aae75aaa0bba85f674bc2248ce2649 Mon Sep 17 00:00:00 2001
From: eson <474420502@qq.com>
Date: Sun, 19 Jun 2022 05:56:05 +0800
Subject: [PATCH] init
---
.gitignore | 94 +++++++
.vscode/settings.json | 3 +
pom.xml | 92 ++++++
src/main/java/com/yuandian/common/Config.java | 263 ++++++++++++++++++
src/main/resources/application.properties | 6 +
.../java/com/yuandian/common/ConfigTest.java | 99 +++++++
6 files changed, 557 insertions(+)
create mode 100644 .gitignore
create mode 100644 .vscode/settings.json
create mode 100644 pom.xml
create mode 100644 src/main/java/com/yuandian/common/Config.java
create mode 100644 src/main/resources/application.properties
create mode 100644 src/test/java/com/yuandian/common/ConfigTest.java
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fe0df52
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,94 @@
+# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
+
+# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,java,maven
+# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,java,maven
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
+
+# Eclipse m2e generated files
+# Eclipse Core
+.project
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+.ionide
+
+# Support for Project snippet scope
+.vscode/*.code-snippets
+
+# Ignore code-workspaces
+*.code-workspace
+
+# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,java,maven
+
+# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
+
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..e0f15db
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "automatic"
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..69aff39
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,92 @@
+
+ 4.0.0
+ com.yuandian.common
+ config
+ 1.0.0-SNAPSHOT
+ jar
+ config
+ http://yuandian.com
+
+ UTF-8
+ 17
+ 17
+ 17
+ 2.1.0
+ 1.30
+ 1.7.36
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.8.2
+ test
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
+
+
+
+ com.alibaba.nacos
+ nacos-client
+ ${nacos.version}
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ provided
+
+
+
+
+
+ yuandian-nexus
+ yuandian-snapshots
+ http://mvn.yuandian.com/repository/maven-snapshots
+
+
+ yuandian-nexus
+ yuandian-public
+ http://mvn.yuandian.com/repository/maven-public
+
+
+
+
+
+ org.sonatype.plugins
+ nxrm3-maven-plugin
+ 1.0.4
+
+
+ default-deploy
+ deploy
+
+ deploy
+
+
+
+
+ http://mvn.yuandian.com
+
+ yuandian-nexus
+
+ maven-snapshots
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/yuandian/common/Config.java b/src/main/java/com/yuandian/common/Config.java
new file mode 100644
index 0000000..63a3369
--- /dev/null
+++ b/src/main/java/com/yuandian/common/Config.java
@@ -0,0 +1,263 @@
+/**
+ * description
+ *
+ * @author eson
+ *2022年6月15日-17:38:16
+ */
+package com.yuandian.common;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
+import org.yaml.snakeyaml.Yaml;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.PropertyKeyConst;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.config.listener.Listener;
+import com.alibaba.nacos.api.exception.NacosException;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+/**
+ * description nacos配置.
+ *
+ * @author eson
+ *2022年6月13日-17:08:46
+ */
+@Slf4j
+@Getter
+@Setter
+public class Config {
+ public static String DEFAULT_CONFIT_FILE = "application.properties";
+ 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";
+ // 所有生成的nacos客户端
+ private static HashMap configDict = new HashMap<>();
+
+ // 配置的所有值主类
+ public Map data;
+ // nacos地址
+ public String serverAddr ;
+ // nacos dataId
+ public String dataId ;
+ // nacos group
+ public String group ;
+ // 线程安全配置锁
+ private Lock datalock;
+ // nacos 客户端类
+ private ConfigService configService;
+ private Config(String GroupAndDataId) throws Exception {
+ String[] gad = GroupAndDataId.split("\\.");
+ if(gad.length != 2) {
+ throw new Exception("Group 或者 DataId 不能存在 '.' 的命令");
+ }
+ this.group = gad[0] + ENV_TEST;
+ this.dataId = gad[1] + ENV_TEST;
+ connect();
+ }
+ /**
+ * 连接nacos
+ * @throws IOException
+ * @throws NacosException
+ */
+ private void connect() throws IOException, NacosException {
+ if(configService != null) {
+ configService.shutDown();
+ configService = null;
+ }
+ // 获取 app
+ Properties prop = new Properties();
+ prop.load(Config.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIT_FILE));
+
+ 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)new Yaml().load(configInfo);
+ log.debug("{}",data);
+ } finally {
+ datalock.unlock();
+ }
+ }
+
+ @Override
+ public Executor getExecutor() {
+ return null;
+ }
+ });
+ }
+ /**
+ * 根据多个key获取yaml的值 keys 路径
+ * @param keys 获取的key值
+ * @return
+ */
+ public Object get(String ...keys) {
+ var cur = data;
+ for(var i = 0; i < keys.length - 1;i++ ) {
+ var key = keys[i];
+ cur = (Map) cur.get(key);
+ }
+ return cur.get(keys[keys.length - 1]);
+ }
+ /**
+ *
+ * 用于定位keys的路径后的操作. 创建keys后赋值. 如果存在keys, 可以直接赋值, 不存在则直接报错
+ *
+ * @author eson
+ *2022年6月15日-下午12:06:37
+ */
+ public class Operator {
+ Config config;
+ String[] keys;
+ Operator(Config config, String[] keys) {
+ this.config = config;
+ this.keys = keys;
+ }
+ /**
+ * 创建seek的key
+ * @return
+ */
+ public Operator createKeys() {
+ var cur = config.data;
+ for(var i = 0; i < keys.length;i++ ) {
+ var key = keys[i];
+ var vobj = cur.get(key);
+ if (vobj == null) {
+ vobj = new LinkedHashMap<>();
+ cur.put(key, vobj);
+ }
+ cur = (Map) vobj;
+ }
+ return this;
+ }
+ /**
+ * 定位后赋值
+ * @param value
+ */
+ public void set(Object value) {
+ var cur = config.data;
+ for(var i = 0; i < keys.length - 1;i++ ) {
+ var key = keys[i];
+ cur = (Map) cur.get(key);
+ }
+ cur.put(keys[keys.length - 1], value);
+ }
+ }
+ /**
+ * 定位. eg. seek("key1", "key2")
+ * @param keys
+ * @return
+ */
+ public Operator seek(String ...keys) {
+ return new Operator(this, keys);
+ }
+ /**
+ * 删除 key的值. 类型map操作. keys是一个路径 remove("a","b") --> {"a": {"b": 1}} 删除b
+ * @param keys
+ * @return
+ */
+ public Object remove(String ...keys) {
+ var cur = data;
+ for(var i = 0; i < keys.length - 1;i++ ) {
+ var key = keys[i];
+ cur = (Map) cur.get(key);
+ }
+ return cur.remove(keys[keys.length - 1]);
+ }
+ /**
+ * 更新配置
+ * @return 返回是否发布成功.
+ * @throws NacosException
+ */
+ public Boolean update() throws NacosException {
+ return configService.publishConfig(dataId, group,new Yaml().dumpAsMap(data));
+ }
+ public static String ENV_TEST = "";
+ /**
+ * 统一使用配置的入口函数 线程安全
+ * @param GroupAndDataID 使用配置的标签 eg."group.dataId"
+ * @param execute 匿名函数
+ * @return 函数返回的值, 如果不需要直接返回null
+ * @throws Exception
+ */
+ public static Object UseConfig(String GroupAndDataID, Function execute) throws Exception {
+ log.info(GroupAndDataID);
+ Config cnf;
+ synchronized(configDict) {
+ cnf = configDict.get(GroupAndDataID);
+ if(cnf == null) {
+ cnf = new Config(GroupAndDataID);
+ configDict.put(GroupAndDataID, cnf);
+ }
+ }
+ try {
+ cnf.datalock.lock();
+ var res = execute.apply(cnf);
+ return res;
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ cnf.datalock.unlock();
+ }
+ }
+ /**
+ * 统一使用配置的入口函数 线程安全
+ * @param execute 统一使用配置的入口匿名方法
+ * @return 函数返回的值, 如果不需要直接返回null
+ * @throws Exception
+ */
+ public static Object UseConfig(Function execute) throws Exception {
+ return UseConfig(DEFAULT_GROUP_DATAID, execute);
+ }
+ private static String Trim(String o, String mychars){
+ if(o == null) {
+ return null;
+ } else if (o.length() == 0) {
+ return o;
+ }
+ var buf = o.toCharArray();
+ var chars = mychars.toCharArray();
+ var start = 0;
+ for( ; start < buf.length; start++) {
+ for(var c: chars){
+ if(buf[start] != c) {
+ break;
+ }
+ }
+ }
+ var end = buf.length;
+ for( ; end >= 0; end--) {
+ for(var c: chars){
+ if(buf[start] != c) {
+ break;
+ }
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..3f68077
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+server.port=3440
+
+yuandian.dataflow.config.nacos.server.addr="192.168.1.113:8848"
+yuandian.dataflow.config.nacos.server.addr-test="192.168.1.113:8848"
+
+
\ No newline at end of file
diff --git a/src/test/java/com/yuandian/common/ConfigTest.java b/src/test/java/com/yuandian/common/ConfigTest.java
new file mode 100644
index 0000000..754ab5f
--- /dev/null
+++ b/src/test/java/com/yuandian/common/ConfigTest.java
@@ -0,0 +1,99 @@
+package com.yuandian.common;
+
+import java.time.Instant;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.yuandian.common.Config;
+
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
+@TestMethodOrder(OrderAnnotation.class)
+public class ConfigTest {
+ /**
+ * 测试配置基础用法
+ * @throws Exception
+ */
+ @Test
+ @Order(1)
+ void testUseConfig() throws Exception {
+ Config.ENV_TEST = "-test";
+ Config.UseConfig((cnf) -> {
+ log.info("{}",cnf.data);
+
+ Assertions.assertEquals(cnf.get("key1", "key2"), "key_path");
+ Instant now = Instant.now();
+ cnf.data.put("use_config", now.toString());
+ try {
+ log.info("{}",cnf.update());
+ } catch (NacosException e) {
+ e.printStackTrace();
+ }
+ return null;
+ });
+ }
+ @Test
+ @Order(2)
+ void testRemove() throws Exception {
+ Config.ENV_TEST = "-test";
+ Config.UseConfig((cnf) -> {
+ cnf.remove("create1", "create2");
+ try {
+ log.info("{}",cnf.update()); // 所有增加删除操作要最后同步到nacos. 都需要update
+ } catch (NacosException e) {
+ e.printStackTrace();
+ }
+ cnf.remove("create1");
+ try {
+ log.info("{}",cnf.update()); // 所有增加删除操作要最后同步到nacos. 都需要update
+ } catch (NacosException e) {
+ e.printStackTrace();
+ }
+ return null;
+ });
+ }
+ @Test
+ @Order(3)
+ void testCreateKeys() throws Exception {
+ Config.ENV_TEST = "-test";
+
+ Config.UseConfig((cnf) -> {
+ log.info("{}",cnf.data);
+ cnf.seek("create1", "create2", "create3").createKeys().set(Instant.now().toString());;
+ try {
+ log.info("{}",cnf.update()); // 所有增加删除操作要最后同步到nacos. 都需要update
+ } catch (NacosException e) {
+ e.printStackTrace();
+ }
+ return null;
+ });
+ }
+
+ @Test
+ @Order(1)
+ void testUpdate() throws Exception {
+ Config.ENV_TEST = "-test";
+ Config.UseConfig((cnf) -> {
+ Instant now = Instant.now();
+ cnf.data.put("use_config", now.toString());
+ try {
+ log.info("{}",cnf.update());
+ } catch (NacosException e) {
+ e.printStackTrace();
+ }
+ return null;
+ });
+ }
+ @Test
+ @Order(1)
+ void testLabelConfig() throws Exception {
+ Config.UseConfig("org.fortest", (cnf)->{
+ log.info("{}", cnf.get("test"));
+ Assertions.assertEquals(cnf.get("test"), "groupAndDataId");
+ return null;
+ });
+ }
+}
\ No newline at end of file