From 80ac58578751d4d3217ca8337ed602769cef6411 Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 18:57:37 +0800 Subject: [PATCH 01/13] =?UTF-8?q?refactor(config):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=B1=BB=E4=B8=AD=E7=9A=84=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=92=8C=E6=96=B9=E6=B3=95=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apollo/biz/config/BizConfig.java | 21 +++--- .../common/config/RefreshableConfig.java | 10 +++ .../portal/component/config/PortalConfig.java | 66 +++++++------------ 3 files changed, 40 insertions(+), 57 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java index 03ebc86a1b1..cae06d1158a 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java @@ -67,6 +67,8 @@ public class BizConfig extends RefreshableConfig { private static final Gson GSON = new Gson(); + private static final TimeUnit INTERVAL_TIME_UNIT = TimeUnit.SECONDS; + private static final Type appIdValueLengthOverrideTypeReference = new TypeToken>() {}.getType(); private static final Type namespaceValueLengthOverrideTypeReference = @@ -140,7 +142,7 @@ public int namespaceNumLimit() { } public Set namespaceNumLimitWhite() { - return Sets.newHashSet(getArrayProperty("namespace.num.limit.white", new String[0])); + return Sets.newHashSet(getArrayProperty("namespace.num.limit.white", EMPTY_STRING_ARRAY)); } public boolean isItemNumLimitEnabled() { @@ -163,7 +165,7 @@ public int appNamespaceCacheScanInterval() { } public TimeUnit appNamespaceCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int appNamespaceCacheRebuildInterval() { @@ -173,7 +175,7 @@ public int appNamespaceCacheRebuildInterval() { } public TimeUnit appNamespaceCacheRebuildIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyCacheScanInterval() { @@ -183,7 +185,7 @@ public int accessKeyCacheScanInterval() { } public TimeUnit accessKeyCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyCacheRebuildInterval() { @@ -193,7 +195,7 @@ public int accessKeyCacheRebuildInterval() { } public TimeUnit accessKeyCacheRebuildIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyAuthTimeDiffTolerance() { @@ -222,7 +224,7 @@ public int releaseMessageCacheScanInterval() { } public TimeUnit releaseMessageCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int releaseMessageScanIntervalInMilli() { @@ -285,13 +287,6 @@ public boolean isConfigServiceIncrementalChangeEnabled() { return getBooleanProperty("config-service.incremental.change.enabled", false); } - int checkInt(int value, int min, int max, int defaultValue) { - if (value >= min && value <= max) { - return value; - } - return defaultValue; - } - public boolean isAdminServiceAccessControlEnabled() { return getBooleanProperty("admin-service.access.control.enabled", false); } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index b68403a0e8b..c6e4d084b39 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -46,6 +46,7 @@ public abstract class RefreshableConfig implements DisposableBean { private static final int CONFIG_REFRESH_INTERVAL = 60; protected Splitter splitter = Splitter.on(LIST_SEPARATOR).omitEmptyStrings().trimResults(); + protected static final String[] EMPTY_STRING_ARRAY = new String[0]; @Autowired private ConfigurableEnvironment environment; @@ -137,4 +138,13 @@ public String getValue(String key) { return environment.getProperty(key); } + protected int checkInt(int value, int min, int max, int defaultValue) { + if (value >= min && value <= max) { + return value; + } + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", + value, min, max, defaultValue); + return defaultValue; + } + } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index eb0b1082e40..3dfe6158a78 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -48,6 +48,13 @@ public class PortalConfig extends RefreshableConfig { private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND = 10; // 10s + private static final int DEFAULT_CONNECT_TIMEOUT = 3000; + private static final int DEFAULT_READ_TIMEOUT = 10000; + private static final int DEFAULT_CONNECTION_TIME_TO_LIVE = -1; + private static final int DEFAULT_CONNECT_POOL_MAX_TOTAL = 20; + private static final int DEFAULT_CONNECT_POOL_MAX_PER_ROUTE = 2; + private static final int DEFAULT_PER_ENV_SEARCH_MAX_RESULTS = 200; + private static final Gson GSON = new Gson(); private static final Type ORGANIZATION = new TypeToken>() {}.getType(); @@ -90,7 +97,7 @@ public List portalSupportedEnvs() { } public int getPerEnvSearchMaxResults() { - return getIntProperty("apollo.portal.search.perEnvMaxResults", 200); + return getIntProperty("apollo.portal.search.perEnvMaxResults", DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); } /** @@ -124,32 +131,22 @@ public List superAdmins() { } public Set emailSupportedEnvs() { - String[] configurations = getArrayProperty("email.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return getEnvSetProperty("email.supported.envs", null); } public Set webHookSupportedEnvs() { - String[] configurations = getArrayProperty("webhook.supported.envs", null); + return getEnvSetProperty("webhook.supported.envs", null); + } + private Set getEnvSetProperty(String key, String[] defaultValue) { + String[] configurations = getArrayProperty(key, defaultValue); Set result = Sets.newHashSet(); - if (configurations == null) { + if (configurations == null || configurations.length == 0) { return result; } - for (String env : configurations) { result.add(Env.valueOf(env)); } - return result; } @@ -163,7 +160,7 @@ public boolean isConfigViewMemberOnly(String env) { String normalizedEnv = transformedEnv.getName(); String[] configViewMemberOnlyEnvs = - getArrayProperty("configView.memberOnly.envs", new String[0]); + getArrayProperty("configView.memberOnly.envs", EMPTY_STRING_ARRAY); for (String memberOnlyEnv : configViewMemberOnlyEnvs) { // Normalize configured env as well for consistent comparison @@ -180,23 +177,23 @@ public boolean isConfigViewMemberOnly(String env) { * Level: normal **/ public int connectTimeout() { - return getIntProperty("api.connectTimeout", 3000); + return getIntProperty("api.connectTimeout", DEFAULT_CONNECT_TIMEOUT); } public int readTimeout() { - return getIntProperty("api.readTimeout", 10000); + return getIntProperty("api.readTimeout", DEFAULT_READ_TIMEOUT); } public int connectionTimeToLive() { - return getIntProperty("api.connectionTimeToLive", -1); + return getIntProperty("api.connectionTimeToLive", DEFAULT_CONNECTION_TIME_TO_LIVE); } public int connectPoolMaxTotal() { - return getIntProperty("api.pool.max.total", 20); + return getIntProperty("api.pool.max.total", DEFAULT_CONNECT_POOL_MAX_TOTAL); } public int connectPoolMaxPerRoute() { - return getIntProperty("api.pool.max.per.route", 2); + return getIntProperty("api.pool.max.per.route", DEFAULT_CONNECT_POOL_MAX_PER_ROUTE); } public List organizations() { @@ -228,7 +225,7 @@ public boolean isEmergencyPublishAllowed(Env env) { String targetEnv = env.getName(); String[] emergencyPublishSupportedEnvs = - getArrayProperty("emergencyPublish.supported.envs", new String[0]); + getArrayProperty("emergencyPublish.supported.envs", EMPTY_STRING_ARRAY); for (String supportedEnv : emergencyPublishSupportedEnvs) { if (Objects.equals(targetEnv, supportedEnv.toUpperCase().trim())) { @@ -243,18 +240,7 @@ public boolean isEmergencyPublishAllowed(Env env) { * Level: low **/ public Set publishTipsSupportedEnvs() { - String[] configurations = getArrayProperty("namespace.publish.tips.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return getEnvSetProperty("namespace.publish.tips.supported.envs", null); } public String consumerTokenSalt() { @@ -337,12 +323,4 @@ public List getUserPasswordNotAllowList() { return Arrays.asList(value); } - private int checkInt(int value, int min, int max, int defaultValue) { - if (value >= min && value <= max) { - return value; - } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", - value, min, max, defaultValue); - return defaultValue; - } } From 03ca6d0d696ce567ffca993e608d46fedd4c45d6 Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 19:08:19 +0800 Subject: [PATCH 02/13] =?UTF-8?q?refactor(config):=20=E8=A1=A5=E5=85=85CHA?= =?UTF-8?q?NGES.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 98baa871494..2c00d2cae68 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Release Notes. Apollo 3.0.0 ------------------ +* [Refactor: extract config constants and methods in BizConfig, PortalConfig, and RefreshableConfig](https://github.com/apolloconfig/apollo/pull/5583) * [Fix: include super admin in hasAnyPermission semantics](https://github.com/apolloconfig/apollo/pull/5568) ------------------ From 0d0e8c20d293c05c1de9923b89713df8ace89dea Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 23:09:40 +0800 Subject: [PATCH 03/13] =?UTF-8?q?refactor(config):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=88=B7=E6=96=B0=E5=8A=9F=E8=83=BD=E5=B9=B6?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=96=B9=E6=B3=95=E5=8F=AF=E8=A7=81=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/RefreshableConfig.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index c6e4d084b39..856c54f4489 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -16,12 +16,15 @@ */ package com.ctrip.framework.apollo.common.config; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; - import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import com.ctrip.framework.apollo.tracer.Tracer; - +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import jakarta.annotation.PostConstruct; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; @@ -29,13 +32,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.CollectionUtils; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import jakarta.annotation.PostConstruct; - public abstract class RefreshableConfig implements DisposableBean { @@ -75,8 +71,7 @@ public void setup() { } // task to update configs - executorService = - Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); + executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); executorService.scheduleWithFixedDelay(() -> { try { @@ -138,12 +133,11 @@ public String getValue(String key) { return environment.getProperty(key); } - protected int checkInt(int value, int min, int max, int defaultValue) { + public int checkInt(int value, int min, int max, int defaultValue) { if (value >= min && value <= max) { return value; } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", - value, min, max, defaultValue); + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); return defaultValue; } From eab6fdcf135148624a2ea2eb5b5ff601f0cd339f Mon Sep 17 00:00:00 2001 From: yangzl Date: Fri, 20 Mar 2026 10:39:33 +0800 Subject: [PATCH 04/13] =?UTF-8?q?style(config):=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E4=BB=A5=E7=AC=A6=E5=90=88=E5=9B=A2?= =?UTF-8?q?=E9=98=9F=E6=A0=B7=E5=BC=8F=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/apollo/common/config/RefreshableConfig.java | 6 ++++-- .../apollo/portal/component/config/PortalConfig.java | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index 856c54f4489..e5cb356878c 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -71,7 +71,8 @@ public void setup() { } // task to update configs - executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); + executorService = + Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); executorService.scheduleWithFixedDelay(() -> { try { @@ -137,7 +138,8 @@ public int checkInt(int value, int min, int max, int defaultValue) { if (value >= min && value <= max) { return value; } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", + value, min, max, defaultValue); return defaultValue; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 3dfe6158a78..86b6a45a65b 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -97,7 +97,8 @@ public List portalSupportedEnvs() { } public int getPerEnvSearchMaxResults() { - return getIntProperty("apollo.portal.search.perEnvMaxResults", DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); + return getIntProperty("apollo.portal.search.perEnvMaxResults", + DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); } /** From 15ec90dbfa4f38507de4f069319fa5445e08c91d Mon Sep 17 00:00:00 2001 From: yangzl Date: Fri, 20 Mar 2026 16:27:00 +0800 Subject: [PATCH 05/13] =?UTF-8?q?fix(config):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E9=85=8D=E7=BD=AE=E8=A7=A3=E6=9E=90=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E7=A9=BA=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apollo/portal/component/config/PortalConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 86b6a45a65b..03fbd19d0fa 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -146,7 +146,11 @@ private Set getEnvSetProperty(String key, String[] defaultValue) { return result; } for (String env : configurations) { - result.add(Env.valueOf(env)); + String envName = env.trim(); + if (envName.isEmpty()) { + continue; + } + result.add(Env.valueOf(envName)); } return result; } From 9a8bc37ad4252b9fb3eceed03e9daf9debd875ce Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 18:57:37 +0800 Subject: [PATCH 06/13] =?UTF-8?q?refactor(config):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=B1=BB=E4=B8=AD=E7=9A=84=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=92=8C=E6=96=B9=E6=B3=95=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apollo/biz/config/BizConfig.java | 21 +++--- .../common/config/RefreshableConfig.java | 10 +++ .../portal/component/config/PortalConfig.java | 66 +++++++------------ 3 files changed, 40 insertions(+), 57 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java index 03ebc86a1b1..cae06d1158a 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java @@ -67,6 +67,8 @@ public class BizConfig extends RefreshableConfig { private static final Gson GSON = new Gson(); + private static final TimeUnit INTERVAL_TIME_UNIT = TimeUnit.SECONDS; + private static final Type appIdValueLengthOverrideTypeReference = new TypeToken>() {}.getType(); private static final Type namespaceValueLengthOverrideTypeReference = @@ -140,7 +142,7 @@ public int namespaceNumLimit() { } public Set namespaceNumLimitWhite() { - return Sets.newHashSet(getArrayProperty("namespace.num.limit.white", new String[0])); + return Sets.newHashSet(getArrayProperty("namespace.num.limit.white", EMPTY_STRING_ARRAY)); } public boolean isItemNumLimitEnabled() { @@ -163,7 +165,7 @@ public int appNamespaceCacheScanInterval() { } public TimeUnit appNamespaceCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int appNamespaceCacheRebuildInterval() { @@ -173,7 +175,7 @@ public int appNamespaceCacheRebuildInterval() { } public TimeUnit appNamespaceCacheRebuildIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyCacheScanInterval() { @@ -183,7 +185,7 @@ public int accessKeyCacheScanInterval() { } public TimeUnit accessKeyCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyCacheRebuildInterval() { @@ -193,7 +195,7 @@ public int accessKeyCacheRebuildInterval() { } public TimeUnit accessKeyCacheRebuildIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int accessKeyAuthTimeDiffTolerance() { @@ -222,7 +224,7 @@ public int releaseMessageCacheScanInterval() { } public TimeUnit releaseMessageCacheScanIntervalTimeUnit() { - return TimeUnit.SECONDS; + return INTERVAL_TIME_UNIT; } public int releaseMessageScanIntervalInMilli() { @@ -285,13 +287,6 @@ public boolean isConfigServiceIncrementalChangeEnabled() { return getBooleanProperty("config-service.incremental.change.enabled", false); } - int checkInt(int value, int min, int max, int defaultValue) { - if (value >= min && value <= max) { - return value; - } - return defaultValue; - } - public boolean isAdminServiceAccessControlEnabled() { return getBooleanProperty("admin-service.access.control.enabled", false); } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index b68403a0e8b..c6e4d084b39 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -46,6 +46,7 @@ public abstract class RefreshableConfig implements DisposableBean { private static final int CONFIG_REFRESH_INTERVAL = 60; protected Splitter splitter = Splitter.on(LIST_SEPARATOR).omitEmptyStrings().trimResults(); + protected static final String[] EMPTY_STRING_ARRAY = new String[0]; @Autowired private ConfigurableEnvironment environment; @@ -137,4 +138,13 @@ public String getValue(String key) { return environment.getProperty(key); } + protected int checkInt(int value, int min, int max, int defaultValue) { + if (value >= min && value <= max) { + return value; + } + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", + value, min, max, defaultValue); + return defaultValue; + } + } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index eb0b1082e40..3dfe6158a78 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -48,6 +48,13 @@ public class PortalConfig extends RefreshableConfig { private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND = 10; // 10s + private static final int DEFAULT_CONNECT_TIMEOUT = 3000; + private static final int DEFAULT_READ_TIMEOUT = 10000; + private static final int DEFAULT_CONNECTION_TIME_TO_LIVE = -1; + private static final int DEFAULT_CONNECT_POOL_MAX_TOTAL = 20; + private static final int DEFAULT_CONNECT_POOL_MAX_PER_ROUTE = 2; + private static final int DEFAULT_PER_ENV_SEARCH_MAX_RESULTS = 200; + private static final Gson GSON = new Gson(); private static final Type ORGANIZATION = new TypeToken>() {}.getType(); @@ -90,7 +97,7 @@ public List portalSupportedEnvs() { } public int getPerEnvSearchMaxResults() { - return getIntProperty("apollo.portal.search.perEnvMaxResults", 200); + return getIntProperty("apollo.portal.search.perEnvMaxResults", DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); } /** @@ -124,32 +131,22 @@ public List superAdmins() { } public Set emailSupportedEnvs() { - String[] configurations = getArrayProperty("email.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return getEnvSetProperty("email.supported.envs", null); } public Set webHookSupportedEnvs() { - String[] configurations = getArrayProperty("webhook.supported.envs", null); + return getEnvSetProperty("webhook.supported.envs", null); + } + private Set getEnvSetProperty(String key, String[] defaultValue) { + String[] configurations = getArrayProperty(key, defaultValue); Set result = Sets.newHashSet(); - if (configurations == null) { + if (configurations == null || configurations.length == 0) { return result; } - for (String env : configurations) { result.add(Env.valueOf(env)); } - return result; } @@ -163,7 +160,7 @@ public boolean isConfigViewMemberOnly(String env) { String normalizedEnv = transformedEnv.getName(); String[] configViewMemberOnlyEnvs = - getArrayProperty("configView.memberOnly.envs", new String[0]); + getArrayProperty("configView.memberOnly.envs", EMPTY_STRING_ARRAY); for (String memberOnlyEnv : configViewMemberOnlyEnvs) { // Normalize configured env as well for consistent comparison @@ -180,23 +177,23 @@ public boolean isConfigViewMemberOnly(String env) { * Level: normal **/ public int connectTimeout() { - return getIntProperty("api.connectTimeout", 3000); + return getIntProperty("api.connectTimeout", DEFAULT_CONNECT_TIMEOUT); } public int readTimeout() { - return getIntProperty("api.readTimeout", 10000); + return getIntProperty("api.readTimeout", DEFAULT_READ_TIMEOUT); } public int connectionTimeToLive() { - return getIntProperty("api.connectionTimeToLive", -1); + return getIntProperty("api.connectionTimeToLive", DEFAULT_CONNECTION_TIME_TO_LIVE); } public int connectPoolMaxTotal() { - return getIntProperty("api.pool.max.total", 20); + return getIntProperty("api.pool.max.total", DEFAULT_CONNECT_POOL_MAX_TOTAL); } public int connectPoolMaxPerRoute() { - return getIntProperty("api.pool.max.per.route", 2); + return getIntProperty("api.pool.max.per.route", DEFAULT_CONNECT_POOL_MAX_PER_ROUTE); } public List organizations() { @@ -228,7 +225,7 @@ public boolean isEmergencyPublishAllowed(Env env) { String targetEnv = env.getName(); String[] emergencyPublishSupportedEnvs = - getArrayProperty("emergencyPublish.supported.envs", new String[0]); + getArrayProperty("emergencyPublish.supported.envs", EMPTY_STRING_ARRAY); for (String supportedEnv : emergencyPublishSupportedEnvs) { if (Objects.equals(targetEnv, supportedEnv.toUpperCase().trim())) { @@ -243,18 +240,7 @@ public boolean isEmergencyPublishAllowed(Env env) { * Level: low **/ public Set publishTipsSupportedEnvs() { - String[] configurations = getArrayProperty("namespace.publish.tips.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return getEnvSetProperty("namespace.publish.tips.supported.envs", null); } public String consumerTokenSalt() { @@ -337,12 +323,4 @@ public List getUserPasswordNotAllowList() { return Arrays.asList(value); } - private int checkInt(int value, int min, int max, int defaultValue) { - if (value >= min && value <= max) { - return value; - } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", - value, min, max, defaultValue); - return defaultValue; - } } From 03ba49d791b072d92b9ea3d83962020d5fce237f Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 19:08:19 +0800 Subject: [PATCH 07/13] =?UTF-8?q?refactor(config):=20=E8=A1=A5=E5=85=85CHA?= =?UTF-8?q?NGES.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index efe072a6613..5df215c94cd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Release Notes. Apollo 3.0.0 ------------------ +* [Refactor: extract config constants and methods in BizConfig, PortalConfig, and RefreshableConfig](https://github.com/apolloconfig/apollo/pull/5583) * [Fix: include super admin in hasAnyPermission semantics](https://github.com/apolloconfig/apollo/pull/5568) * [Change: official Config/Admin packages now default to database discovery; upgraded Eureka deployments should explicitly keep the `github` profile to preserve legacy behavior](https://github.com/apolloconfig/apollo/pull/5580) From 8e2d29637cbc0e403fe546e45520b41b4018d463 Mon Sep 17 00:00:00 2001 From: yangzl Date: Thu, 19 Mar 2026 23:09:40 +0800 Subject: [PATCH 08/13] =?UTF-8?q?refactor(config):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=88=B7=E6=96=B0=E5=8A=9F=E8=83=BD=E5=B9=B6?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=96=B9=E6=B3=95=E5=8F=AF=E8=A7=81=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/RefreshableConfig.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index c6e4d084b39..856c54f4489 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -16,12 +16,15 @@ */ package com.ctrip.framework.apollo.common.config; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; - import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import com.ctrip.framework.apollo.tracer.Tracer; - +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import jakarta.annotation.PostConstruct; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; @@ -29,13 +32,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.CollectionUtils; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import jakarta.annotation.PostConstruct; - public abstract class RefreshableConfig implements DisposableBean { @@ -75,8 +71,7 @@ public void setup() { } // task to update configs - executorService = - Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); + executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); executorService.scheduleWithFixedDelay(() -> { try { @@ -138,12 +133,11 @@ public String getValue(String key) { return environment.getProperty(key); } - protected int checkInt(int value, int min, int max, int defaultValue) { + public int checkInt(int value, int min, int max, int defaultValue) { if (value >= min && value <= max) { return value; } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", - value, min, max, defaultValue); + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); return defaultValue; } From 6e3b579185b8f1f03569aae1e8204ffa6026671b Mon Sep 17 00:00:00 2001 From: yangzl Date: Fri, 20 Mar 2026 10:39:33 +0800 Subject: [PATCH 09/13] =?UTF-8?q?style(config):=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E4=BB=A5=E7=AC=A6=E5=90=88=E5=9B=A2?= =?UTF-8?q?=E9=98=9F=E6=A0=B7=E5=BC=8F=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/apollo/common/config/RefreshableConfig.java | 6 ++++-- .../apollo/portal/component/config/PortalConfig.java | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index 856c54f4489..e5cb356878c 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -71,7 +71,8 @@ public void setup() { } // task to update configs - executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); + executorService = + Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigRefresher", true)); executorService.scheduleWithFixedDelay(() -> { try { @@ -137,7 +138,8 @@ public int checkInt(int value, int min, int max, int defaultValue) { if (value >= min && value <= max) { return value; } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", + value, min, max, defaultValue); return defaultValue; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 3dfe6158a78..86b6a45a65b 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -97,7 +97,8 @@ public List portalSupportedEnvs() { } public int getPerEnvSearchMaxResults() { - return getIntProperty("apollo.portal.search.perEnvMaxResults", DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); + return getIntProperty("apollo.portal.search.perEnvMaxResults", + DEFAULT_PER_ENV_SEARCH_MAX_RESULTS); } /** From 40528defbac59e4847de7fe8f8c27e4309001e06 Mon Sep 17 00:00:00 2001 From: yangzl Date: Fri, 20 Mar 2026 16:27:00 +0800 Subject: [PATCH 10/13] =?UTF-8?q?fix(config):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E9=85=8D=E7=BD=AE=E8=A7=A3=E6=9E=90=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E7=A9=BA=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apollo/portal/component/config/PortalConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 86b6a45a65b..03fbd19d0fa 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -146,7 +146,11 @@ private Set getEnvSetProperty(String key, String[] defaultValue) { return result; } for (String env : configurations) { - result.add(Env.valueOf(env)); + String envName = env.trim(); + if (envName.isEmpty()) { + continue; + } + result.add(Env.valueOf(envName)); } return result; } From db4c19d2f6e5bb2d893efb720c2009420e5e907f Mon Sep 17 00:00:00 2001 From: yangzl Date: Mon, 23 Mar 2026 17:26:48 +0800 Subject: [PATCH 11/13] =?UTF-8?q?refactor(config):=20=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=B8=B8=E9=87=8F=E5=92=8C=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E6=95=B0=E7=BB=84=E5=A4=84=E7=90=86?= =?UTF-8?q?,=E8=A1=A5=E5=85=85=E5=BF=85=E8=A6=81=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 2 +- .../apollo/biz/config/BizConfig.java | 5 +- .../apollo/biz/config/BizConfigTest.java | 13 +++ .../common/config/RefreshableConfig.java | 20 ++++ .../portal/component/config/PortalConfig.java | 46 ++++---- .../component/config/PortalConfigTest.java | 100 ++++++++++++++++++ 6 files changed, 161 insertions(+), 25 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5df215c94cd..28e4a33bdda 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,9 +5,9 @@ Release Notes. Apollo 3.0.0 ------------------ -* [Refactor: extract config constants and methods in BizConfig, PortalConfig, and RefreshableConfig](https://github.com/apolloconfig/apollo/pull/5583) * [Fix: include super admin in hasAnyPermission semantics](https://github.com/apolloconfig/apollo/pull/5568) * [Change: official Config/Admin packages now default to database discovery; upgraded Eureka deployments should explicitly keep the `github` profile to preserve legacy behavior](https://github.com/apolloconfig/apollo/pull/5580) +* [Refactor: extract config constants and methods in BizConfig, PortalConfig, and RefreshableConfig](https://github.com/apolloconfig/apollo/pull/5583) ------------------ All issues and pull requests are [here](https://github.com/apolloconfig/apollo/milestone/18?closed=1) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java index cae06d1158a..452ae0ecac1 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java @@ -38,7 +38,7 @@ @Component public class BizConfig extends RefreshableConfig { - private final static Logger logger = LoggerFactory.getLogger(BizConfig.class); + private static final Logger logger = LoggerFactory.getLogger(BizConfig.class); private static final int DEFAULT_ITEM_KEY_LENGTH = 128; private static final int DEFAULT_ITEM_VALUE_LENGTH = 20000; @@ -142,7 +142,8 @@ public int namespaceNumLimit() { } public Set namespaceNumLimitWhite() { - return Sets.newHashSet(getArrayProperty("namespace.num.limit.white", EMPTY_STRING_ARRAY)); + String[] arr = getArrayProperty("namespace.num.limit.white", EMPTY_STRING_ARRAY); + return Sets.newHashSet(trimAndOmitEmpty(arr)); } public boolean isItemNumLimitEnabled() { diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java index 7913a0a79ea..efe45e05284 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java @@ -34,6 +34,8 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; +import java.util.Set; + /** * @author Jason Song(song_s@ctrip.com) */ @@ -189,4 +191,15 @@ public void testIsConfigServiceCacheKeyIgnoreCase() { when(environment.getProperty("config-service.cache.key.ignore-case")).thenReturn("true"); assertTrue(bizConfig.isConfigServiceCacheKeyIgnoreCase()); } + + @Test + public void testNamespaceNumLimitWhite_filtersEmptyItems() { + when(environment.getProperty("namespace.num.limit.white")).thenReturn("app1,,app2,"); + + Set result = bizConfig.namespaceNumLimitWhite(); + + assertEquals(2, result.size()); + assertTrue(result.contains("app1")); + assertTrue(result.contains("app2")); + } } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index e5cb356878c..12a81cf6206 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -21,6 +21,8 @@ import com.google.common.base.Splitter; import com.google.common.base.Strings; import jakarta.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -91,6 +93,24 @@ public void destroy() { } } + /** + * Trims each element and omits empty strings. Use for comma-separated configs where empty + * items (e.g. from consecutive commas) should be omitted. + */ + protected List trimAndOmitEmpty(String[] arr) { + if (arr == null || arr.length == 0) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (String s : arr) { + String trimmed = s.trim(); + if (!trimmed.isEmpty()) { + result.add(trimmed); + } + } + return result; + } + public int getIntProperty(String key, int defaultValue) { try { String value = getValue(key); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 03fbd19d0fa..62c43a8cda7 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -32,7 +32,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -88,11 +87,9 @@ public List portalSupportedEnvs() { String[] configurations = getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); List envs = Lists.newLinkedList(); - - for (String env : configurations) { - envs.add(Env.addEnvironment(env)); + for (String envName : trimAndOmitEmpty(configurations)) { + envs.add(Env.addEnvironment(envName)); } - return envs; } @@ -142,14 +139,7 @@ public Set webHookSupportedEnvs() { private Set getEnvSetProperty(String key, String[] defaultValue) { String[] configurations = getArrayProperty(key, defaultValue); Set result = Sets.newHashSet(); - if (configurations == null || configurations.length == 0) { - return result; - } - for (String env : configurations) { - String envName = env.trim(); - if (envName.isEmpty()) { - continue; - } + for (String envName : trimAndOmitEmpty(configurations)) { result.add(Env.valueOf(envName)); } return result; @@ -167,7 +157,7 @@ public boolean isConfigViewMemberOnly(String env) { String[] configViewMemberOnlyEnvs = getArrayProperty("configView.memberOnly.envs", EMPTY_STRING_ARRAY); - for (String memberOnlyEnv : configViewMemberOnlyEnvs) { + for (String memberOnlyEnv : trimAndOmitEmpty(configViewMemberOnlyEnvs)) { // Normalize configured env as well for consistent comparison Env configEnv = Env.transformEnv(memberOnlyEnv); if (configEnv != Env.UNKNOWN && configEnv.getName().equals(normalizedEnv)) { @@ -202,10 +192,16 @@ public int connectPoolMaxPerRoute() { } public List organizations() { - String organizations = getValue("organizations"); - return organizations == null ? Collections.emptyList() - : GSON.fromJson(organizations, ORGANIZATION); + if (organizations == null) { + return Collections.emptyList(); + } + try { + return GSON.fromJson(organizations, ORGANIZATION); + } catch (Exception e) { + logger.error("Wrong format for: organizations", e); + return Collections.emptyList(); + } } public String portalAddress() { @@ -227,13 +223,18 @@ public int refreshAdminServerAddressTaskOfflineIntervalSecond() { } public boolean isEmergencyPublishAllowed(Env env) { - String targetEnv = env.getName(); + Env transformedEnv = Env.transformEnv(env.getName()); + if (Env.UNKNOWN == transformedEnv) { + return false; + } + String normalizedEnv = transformedEnv.getName(); String[] emergencyPublishSupportedEnvs = getArrayProperty("emergencyPublish.supported.envs", EMPTY_STRING_ARRAY); - for (String supportedEnv : emergencyPublishSupportedEnvs) { - if (Objects.equals(targetEnv, supportedEnv.toUpperCase().trim())) { + for (String supportedEnv : trimAndOmitEmpty(emergencyPublishSupportedEnvs)) { + Env configEnv = Env.transformEnv(supportedEnv); + if (configEnv != Env.UNKNOWN && configEnv.getName().equals(normalizedEnv)) { return true; } } @@ -322,10 +323,11 @@ public boolean supportSearchByItem() { public List getUserPasswordNotAllowList() { String[] value = getArrayProperty("apollo.portal.auth.user-password-not-allow-list", null); - if (value == null || value.length == 0) { + List filtered = trimAndOmitEmpty(value); + if (filtered.isEmpty()) { return DEFAULT_USER_PASSWORD_NOT_ALLOW_LIST; } - return Arrays.asList(value); + return filtered; } } diff --git a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java index 189e06c73c4..c8f98213156 100644 --- a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java +++ b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java @@ -20,8 +20,10 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -350,4 +352,102 @@ void isConfigViewMemberOnly_multipleEnvs() { // Non-configured env should return false assertThat(portalConfig.isConfigViewMemberOnly("DEV")).isFalse(); } + + @Test + void portalSupportedEnvs_filtersBlankAndEmptyItems() { + // Consecutive commas: "FAT,,UAT,,PRO" -> empty strings between + doReturn(new String[] {"FAT", "", "UAT", "", "PRO"}) + .when(portalConfig) + .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); + + List envs = portalConfig.portalSupportedEnvs(); + + assertThat(envs).hasSize(3); + assertThat(envs.get(0).getName()).isEqualTo("FAT"); + assertThat(envs.get(1).getName()).isEqualTo("UAT"); + assertThat(envs.get(2).getName()).isEqualTo("PRO"); + } + + @Test + void portalSupportedEnvs_filtersLeadingAndTrailingEmptyItems() { + // Leading comma: ",FAT,UAT,PRO" and trailing: "FAT,UAT,PRO," + doReturn(new String[] {"", "FAT", "UAT", "PRO", ""}) + .when(portalConfig) + .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); + + List envs = portalConfig.portalSupportedEnvs(); + + assertThat(envs).hasSize(3); + assertThat(envs.get(0).getName()).isEqualTo("FAT"); + assertThat(envs.get(1).getName()).isEqualTo("UAT"); + assertThat(envs.get(2).getName()).isEqualTo("PRO"); + } + + @Test + void portalSupportedEnvs_filtersWhitespaceOnlyItems() { + // Whitespace-only items should be filtered + doReturn(new String[] {" ", "FAT", " ", "UAT", "\t", "PRO", " "}) + .when(portalConfig) + .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); + + List envs = portalConfig.portalSupportedEnvs(); + + assertThat(envs).hasSize(3); + assertThat(envs.get(0).getName()).isEqualTo("FAT"); + assertThat(envs.get(1).getName()).isEqualTo("UAT"); + assertThat(envs.get(2).getName()).isEqualTo("PRO"); + } + + // ========== getUserPasswordNotAllowList Tests ========== + + /** + * getUserPasswordNotAllowList filters empty items from comma-separated config (e.g. "111,,222,"). + */ + @Test + void getUserPasswordNotAllowList_filtersEmptyItems() { + doReturn(new String[] {"111", "", "222", "", "333"}) + .when(portalConfig) + .getArrayProperty("apollo.portal.auth.user-password-not-allow-list", null); + + List result = portalConfig.getUserPasswordNotAllowList(); + + assertThat(result).containsExactly("111", "222", "333"); + } + + // ========== organizations Tests ========== + + /** + * organizations returns emptyList when JSON is malformed, does not throw. + */ + @Test + void organizations_malformedJson_returnsEmptyList() { + doReturn("{ invalid json }").when(portalConfig).getValue("organizations"); + + List result = portalConfig.organizations(); + + assertThat(result).isEmpty(); + } + + // ========== isEmergencyPublishAllowed Tests ========== + + /** + * isEmergencyPublishAllowed uses Env.transformEnv: prod/PROD/PRO aliases all match. + */ + @Test + void isEmergencyPublishAllowed_prodAliasesMatch() { + doReturn(new String[] {"prod", "", "UAT"}) + .when(portalConfig) + .getArrayProperty("emergencyPublish.supported.envs", new String[0]); + + assertThat(portalConfig.isEmergencyPublishAllowed(Env.PRO)).isTrue(); + } + + @Test + void isEmergencyPublishAllowed_fatAndFwsAliasesMatch() { + doReturn(new String[] {"fat", "FWS"}) + .when(portalConfig) + .getArrayProperty("emergencyPublish.supported.envs", new String[0]); + + assertThat(portalConfig.isEmergencyPublishAllowed(Env.FAT)).isTrue(); + } } From 72deaacda14e07e7d2a9064e0508a1ea224f2e27 Mon Sep 17 00:00:00 2001 From: yangzl Date: Mon, 23 Mar 2026 17:28:50 +0800 Subject: [PATCH 12/13] =?UTF-8?q?chore(build):=20=E6=9B=B4=E6=96=B0=20.git?= =?UTF-8?q?ignore=20=E6=96=87=E4=BB=B6=E4=BB=A5=E5=BF=BD=E7=95=A5=20Gradle?= =?UTF-8?q?=20=E5=92=8C=20VSCode=20=E7=9B=B8=E5=85=B3=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index ece055a1612..9c41590e29b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,12 @@ target .idea *.iml +# Gradle +.gradle/ + +# VSCode +.vscode/ + # git *.orig .flattened-pom.xml From ae6d84e7f7844c737c3adadaaf20fc9035c944fe Mon Sep 17 00:00:00 2001 From: yangzl Date: Mon, 23 Mar 2026 17:34:38 +0800 Subject: [PATCH 13/13] =?UTF-8?q?style(test):=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=20PortalConfigTest=20=E4=B8=AD=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/config/PortalConfigTest.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java index c8f98213156..976ccb5d2d9 100644 --- a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java +++ b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigTest.java @@ -356,8 +356,7 @@ void isConfigViewMemberOnly_multipleEnvs() { @Test void portalSupportedEnvs_filtersBlankAndEmptyItems() { // Consecutive commas: "FAT,,UAT,,PRO" -> empty strings between - doReturn(new String[] {"FAT", "", "UAT", "", "PRO"}) - .when(portalConfig) + doReturn(new String[] {"FAT", "", "UAT", "", "PRO"}).when(portalConfig) .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); List envs = portalConfig.portalSupportedEnvs(); @@ -371,8 +370,7 @@ void portalSupportedEnvs_filtersBlankAndEmptyItems() { @Test void portalSupportedEnvs_filtersLeadingAndTrailingEmptyItems() { // Leading comma: ",FAT,UAT,PRO" and trailing: "FAT,UAT,PRO," - doReturn(new String[] {"", "FAT", "UAT", "PRO", ""}) - .when(portalConfig) + doReturn(new String[] {"", "FAT", "UAT", "PRO", ""}).when(portalConfig) .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); List envs = portalConfig.portalSupportedEnvs(); @@ -386,8 +384,7 @@ void portalSupportedEnvs_filtersLeadingAndTrailingEmptyItems() { @Test void portalSupportedEnvs_filtersWhitespaceOnlyItems() { // Whitespace-only items should be filtered - doReturn(new String[] {" ", "FAT", " ", "UAT", "\t", "PRO", " "}) - .when(portalConfig) + doReturn(new String[] {" ", "FAT", " ", "UAT", "\t", "PRO", " "}).when(portalConfig) .getArrayProperty("apollo.portal.envs", new String[] {"FAT", "UAT", "PRO"}); List envs = portalConfig.portalSupportedEnvs(); @@ -405,8 +402,7 @@ void portalSupportedEnvs_filtersWhitespaceOnlyItems() { */ @Test void getUserPasswordNotAllowList_filtersEmptyItems() { - doReturn(new String[] {"111", "", "222", "", "333"}) - .when(portalConfig) + doReturn(new String[] {"111", "", "222", "", "333"}).when(portalConfig) .getArrayProperty("apollo.portal.auth.user-password-not-allow-list", null); List result = portalConfig.getUserPasswordNotAllowList(); @@ -435,8 +431,7 @@ void organizations_malformedJson_returnsEmptyList() { */ @Test void isEmergencyPublishAllowed_prodAliasesMatch() { - doReturn(new String[] {"prod", "", "UAT"}) - .when(portalConfig) + doReturn(new String[] {"prod", "", "UAT"}).when(portalConfig) .getArrayProperty("emergencyPublish.supported.envs", new String[0]); assertThat(portalConfig.isEmergencyPublishAllowed(Env.PRO)).isTrue(); @@ -444,8 +439,7 @@ void isEmergencyPublishAllowed_prodAliasesMatch() { @Test void isEmergencyPublishAllowed_fatAndFwsAliasesMatch() { - doReturn(new String[] {"fat", "FWS"}) - .when(portalConfig) + doReturn(new String[] {"fat", "FWS"}).when(portalConfig) .getArrayProperty("emergencyPublish.supported.envs", new String[0]); assertThat(portalConfig.isEmergencyPublishAllowed(Env.FAT)).isTrue();