Эх сурвалжийг харах

代码优化;新增framework-kubernetes模块

Woody 1 сар өмнө
parent
commit
ce8d0205a4

+ 6 - 0
framework-cloud-kubernetes/pom.xml

@@ -18,6 +18,7 @@
     <properties>
         <framework-cloud.version>1.0.0-RELEASE</framework-cloud.version>
         <framework-feign.version>1.0.0-RELEASE</framework-feign.version>
+        <framework-kubernetes.version>1.0.0-RELEASE</framework-kubernetes.version>
     </properties>
 
     <dependencies>
@@ -49,6 +50,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>com.chelvc.framework</groupId>
+            <artifactId>framework-kubernetes</artifactId>
+            <version>${framework-kubernetes.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-kubernetes</artifactId>

+ 34 - 0
framework-kubernetes/pom.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.chelvc.framework</groupId>
+        <artifactId>framework-dependencies</artifactId>
+        <version>1.0.0-RELEASE</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>framework-kubernetes</artifactId>
+    <version>1.0.0-RELEASE</version>
+
+    <properties>
+        <client-java.version>18.0.0</client-java.version>
+        <framework-base.version>1.0.0-RELEASE</framework-base.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.kubernetes</groupId>
+            <artifactId>client-java</artifactId>
+            <version>${client-java.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.chelvc.framework</groupId>
+            <artifactId>framework-base</artifactId>
+            <version>${framework-base.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 185 - 0
framework-kubernetes/src/main/java/com/chelvc/framework/kubernetes/context/KubernetesContextHolder.java

@@ -0,0 +1,185 @@
+package com.chelvc.framework.kubernetes.context;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import com.chelvc.framework.base.context.ApplicationContextHolder;
+import com.chelvc.framework.common.util.ObjectUtils;
+import com.chelvc.framework.common.util.StringUtils;
+import com.chelvc.framework.common.util.ThreadUtils;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import io.kubernetes.client.openapi.ApiClient;
+import io.kubernetes.client.openapi.ApiException;
+import io.kubernetes.client.openapi.Configuration;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1ConfigMap;
+import io.kubernetes.client.util.Config;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Kubernetes上下文工具
+ *
+ * @author Woody
+ * @date 2025/3/19
+ */
+@Slf4j
+public final class KubernetesContextHolder {
+    /**
+     * 核心API对象实例
+     */
+    private static final CoreV1Api CORE_API;
+
+    private KubernetesContextHolder() {
+    }
+
+    static {
+        // 初始化默认客户端
+        ApiClient client;
+        try {
+            client = Config.defaultClient();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        Configuration.setDefaultApiClient(client);
+
+        // 初始化核心API对象实例
+        CORE_API = new CoreV1Api();
+    }
+
+    /**
+     * 获取核心API对象实例
+     *
+     * @return 核心API对象实例
+     */
+    public static CoreV1Api getCoreApi() {
+        return CORE_API;
+    }
+
+    /**
+     * 获取配置
+     *
+     * @return 配置键/值映射表
+     */
+    public static Map<String, String> getConfig() {
+        return getConfig(ApplicationContextHolder.getApplicationName(), ApplicationContextHolder.getProfile());
+    }
+
+    /**
+     * 获取配置
+     *
+     * @param name      配置名称
+     * @param namespace 命名空间
+     * @return 配置键/值映射表
+     */
+    public static Map<String, String> getConfig(@NonNull String name, @NonNull String namespace) {
+        V1ConfigMap response;
+        CoreV1Api api = getCoreApi();
+        try {
+            response = api.readNamespacedConfigMap(name, namespace, null);
+        } catch (ApiException e) {
+            throw new RuntimeException(e);
+        }
+        Map<String, String> config = ObjectUtils.ifNull(response, V1ConfigMap::getData);
+        return ObjectUtils.isEmpty(config) ? Collections.emptyMap() : config;
+    }
+
+    /**
+     * 更新配置
+     *
+     * @param key   配置键
+     * @param value 配置值
+     */
+    public static void updateConfig(@NonNull String key, String value) {
+        updateConfig(ApplicationContextHolder.getApplicationName(), ApplicationContextHolder.getProfile(), key, value);
+    }
+
+    /**
+     * 更新配置
+     *
+     * @param name      配置名称
+     * @param namespace 命名空间
+     * @param key       配置键
+     * @param value     配置值
+     */
+    public static void updateConfig(@NonNull String name, @NonNull String namespace, @NonNull String key,
+                                    String value) {
+        updateConfig(name, namespace, ImmutableMap.of(key, ObjectUtils.ifNull(value, StringUtils.EMPTY)));
+    }
+
+    /**
+     * 更新配置
+     *
+     * @param config 配置键/值映射表
+     */
+    public static void updateConfig(@NonNull Map<String, String> config) {
+        updateConfig(ApplicationContextHolder.getApplicationName(), ApplicationContextHolder.getProfile(), config);
+    }
+
+    /**
+     * 更新配置
+     *
+     * @param name      配置名称
+     * @param namespace 命名空间
+     * @param config    配置键/值映射表
+     */
+    public static void updateConfig(@NonNull String name, @NonNull String namespace,
+                                    @NonNull Map<String, String> config) {
+        if (ObjectUtils.isEmpty(config)) {
+            return;
+        }
+
+        int retry = 2;
+        CoreV1Api api = getCoreApi();
+        do {
+            try {
+                V1ConfigMap configmap = api.readNamespacedConfigMap(name, namespace, null);
+                Map<String, String> original = ObjectUtils.ifNull(configmap, V1ConfigMap::getData);
+                Map<String, String> update =
+                        Maps.newHashMapWithExpectedSize(ObjectUtils.size(original) + config.size());
+                if (ObjectUtils.notEmpty(original)) {
+                    update.putAll(original);
+                }
+                config.forEach((key, value) -> {
+                    if (StringUtils.isEmpty(value)) {
+                        update.remove(key);
+                    } else {
+                        update.put(key, value);
+                    }
+                });
+                configmap.setData(update);
+                api.replaceNamespacedConfigMap(name, namespace, configmap, null, null, null, null);
+            } catch (ApiException e) {
+                if (retry == 0) {
+                    throw new RuntimeException(e);
+                }
+                log.warn("Kubernetes configmap replace failed: {}, {}", name, namespace, e);
+                ThreadUtils.sleep(200);
+            }
+        } while (retry-- > 0);
+    }
+
+    /**
+     * 删除配置
+     */
+    public static void removeConfig() {
+        removeConfig(ApplicationContextHolder.getApplicationName(), ApplicationContextHolder.getProfile());
+    }
+
+    /**
+     * 删除配置
+     *
+     * @param name      配置名称
+     * @param namespace 命名空间
+     */
+    public static void removeConfig(@NonNull String name, @NonNull String namespace) {
+        CoreV1Api api = getCoreApi();
+        try {
+            api.deleteNamespacedConfigMap(name, namespace, null, null, null, null, null, null);
+        } catch (ApiException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 64 - 52
framework-nacos/src/main/java/com/chelvc/framework/nacos/context/NacosContextHolder.java

@@ -15,9 +15,11 @@ import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
+import com.chelvc.framework.common.util.ThreadUtils;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * Nacos上下文工具类
@@ -25,6 +27,7 @@ import lombok.NonNull;
  * @author Woody
  * @date 2024/1/30
  */
+@Slf4j
 public final class NacosContextHolder {
     /**
      * 权限配置ID
@@ -108,16 +111,16 @@ public final class NacosContextHolder {
     /**
      * 解析配置信息
      *
-     * @param config 配置信息
+     * @param content 配置信息
      * @return 键/值映射表
      */
-    public static Map<String, String> analyseConfig(String config) {
-        if (StringUtils.isEmpty(config)) {
+    public static Map<String, String> analyseConfig(String content) {
+        if (StringUtils.isEmpty(content)) {
             return Collections.emptyMap();
         }
         char eq = StringUtils.EQUAL.charAt(0);
-        String[] lines = config.split(StringUtils.ENTER);
-        Map<String, String> configuration = Maps.newHashMapWithExpectedSize(lines.length);
+        String[] lines = content.split(StringUtils.ENTER);
+        Map<String, String> config = Maps.newHashMapWithExpectedSize(lines.length);
         for (String line : lines) {
             String key, value;
             int index = line.indexOf(eq);
@@ -125,9 +128,9 @@ public final class NacosContextHolder {
                     || StringUtils.isEmpty(value = line.substring(index + 1).trim())) {
                 continue;
             }
-            configuration.put(key, value);
+            config.put(key, value);
         }
-        return configuration;
+        return config;
     }
 
     /**
@@ -148,18 +151,8 @@ public final class NacosContextHolder {
      *
      * @return 配置键/值映射表
      */
-    public static Map<String, String> getConfiguration() {
-        return getConfiguration(getConfigId());
-    }
-
-    /**
-     * 获取配置
-     *
-     * @param id 配置ID
-     * @return 配置键/值映射表
-     */
-    public static Map<String, String> getConfiguration(@NonNull String id) {
-        return getConfiguration(id, getConfigGroup());
+    public static Map<String, String> getConfig() {
+        return getConfig(getConfigId(), getConfigGroup());
     }
 
     /**
@@ -169,7 +162,7 @@ public final class NacosContextHolder {
      * @param group 配置分组
      * @return 配置键/值映射表
      */
-    public static Map<String, String> getConfiguration(@NonNull String id, @NonNull String group) {
+    public static Map<String, String> getConfig(@NonNull String id, @NonNull String group) {
         String content;
         ConfigService service = getConfigService();
         try {
@@ -181,71 +174,90 @@ public final class NacosContextHolder {
     }
 
     /**
-     * 初始化配置信息
+     * 更新配置
      *
      * @param key   配置键
      * @param value 配置值
      */
-    public static void initializeConfiguration(@NonNull String key, @NonNull String value) {
-        initializeConfiguration(getConfigId(), key, value);
+    public static void updateConfig(@NonNull String key, String value) {
+        updateConfig(getConfigId(), getConfigGroup(), key, value);
     }
 
     /**
-     * 初始化配置信息
+     * 更新配置
      *
      * @param id    配置ID
+     * @param group 配置分组
      * @param key   配置键
      * @param value 配置值
      */
-    public static void initializeConfiguration(@NonNull String id, @NonNull String key, @NonNull String value) {
-        initializeConfiguration(id, getConfigGroup(), key, value);
+    public static void updateConfig(@NonNull String id, @NonNull String group, @NonNull String key, String value) {
+        updateConfig(id, group, ImmutableMap.of(key, ObjectUtils.ifNull(value, StringUtils.EMPTY)));
     }
 
     /**
-     * 初始化配置信息
+     * 更新配置
      *
-     * @param id    配置ID
-     * @param group 配置分组
-     * @param key   配置键
-     * @param value 配置值
+     * @param config 配置键/值映射表
      */
-    public static void initializeConfiguration(@NonNull String id, @NonNull String group, @NonNull String key,
-                                               @NonNull String value) {
-        initializeConfiguration(id, group, ImmutableMap.of(key, value));
+    public static void updateConfig(@NonNull Map<String, String> config) {
+        updateConfig(getConfigId(), getConfigGroup(), config);
     }
 
     /**
-     * 初始化配置信息
+     * 更新配置
      *
-     * @param configuration 配置信息键/值映射表
+     * @param id     配置ID
+     * @param group  配置分组
+     * @param config 配置键/值映射表
      */
-    public static void initializeConfiguration(@NonNull Map<String, String> configuration) {
-        initializeConfiguration(getConfigId(), configuration);
+    public static void updateConfig(@NonNull String id, @NonNull String group, @NonNull Map<String, String> config) {
+        if (ObjectUtils.isEmpty(config)) {
+            return;
+        }
+
+        int retry = 2;
+        ConfigService service = getConfigService();
+        do {
+            try {
+                Map<String, String> original = analyseConfig(service.getConfig(id, group, 3000));
+                Map<String, String> update = Maps.newHashMapWithExpectedSize(original.size() + config.size());
+                update.putAll(original);
+                config.forEach((key, value) -> {
+                    if (StringUtils.isEmpty(value)) {
+                        update.remove(key);
+                    } else {
+                        update.put(key, value);
+                    }
+                });
+                service.publishConfig(id, group, analyseConfig(update));
+            } catch (NacosException e) {
+                if (retry == 0) {
+                    throw new RuntimeException(e);
+                }
+                log.warn("Nacos config publish failed: {}, {}", id, group, e);
+                ThreadUtils.sleep(200);
+            }
+        } while (retry-- > 0);
     }
 
     /**
-     * 初始化配置信息
-     *
-     * @param id            配置ID
-     * @param configuration 配置信息键/值映射表
+     * 删除配置
      */
-    public static void initializeConfiguration(@NonNull String id, @NonNull Map<String, String> configuration) {
-        initializeConfiguration(id, getConfigGroup(), configuration);
+    public static void removeConfig() {
+        removeConfig(getConfigId(), getConfigGroup());
     }
 
     /**
-     * 初始化配置信息
+     * 删除配置
      *
-     * @param id            配置ID
-     * @param group         配置分组
-     * @param configuration 配置信息键/值映射表
+     * @param id    配置ID
+     * @param group 配置分组
      */
-    public static void initializeConfiguration(@NonNull String id, @NonNull String group,
-                                               @NonNull Map<String, String> configuration) {
+    public static void removeConfig(@NonNull String id, @NonNull String group) {
         ConfigService service = getConfigService();
-        String content = analyseConfig(configuration);
         try {
-            service.publishConfig(id, group, content);
+            service.removeConfig(id, group);
         } catch (NacosException e) {
             throw new RuntimeException(e);
         }

+ 1 - 0
pom.xml

@@ -30,6 +30,7 @@
         <module>framework-upload</module>
         <module>framework-wechat</module>
         <module>framework-download</module>
+        <module>framework-kubernetes</module>
         <module>framework-elasticsearch</module>
         <module>framework-dependencies</module>
         <module>framework-cloud</module>