From d45ba449ca6ae001c0717b2d431e00282c14123b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BA=91=E9=A3=9E?= <674619459@qq.com> Date: Mon, 16 Jan 2023 10:04:24 +0800 Subject: [PATCH 1/5] [ISSUE #8460]add config change plugin (#9820) --- config/pom.xml | 5 + .../server/aspect/ConfigChangeAspect.java | 398 ++++++++++++++++++ .../configuration/ConfigChangeConfigs.java | 166 ++++++++ .../config/server/utils/ConfigExecutor.java | 13 +- .../ConfigChangeConfigsTest.java | 98 +++++ .../src/main/resources/application.properties | 13 + plugin/config/pom.xml | 40 ++ .../config/ConfigChangePluginManager.java | 137 ++++++ .../constants/ConfigChangeConstants.java | 120 ++++++ .../constants/ConfigChangeExecuteTypes.java | 37 ++ .../constants/ConfigChangePointCutTypes.java | 64 +++ .../config/model/ConfigChangeRequest.java | 53 +++ .../config/model/ConfigChangeResponse.java | 72 ++++ .../config/spi/ConfigChangePluginService.java | 76 ++++ .../ConfigChangePluginManagerTests.java | 131 ++++++ plugin/pom.xml | 1 + pom.xml | 5 + 17 files changed, 1427 insertions(+), 2 deletions(-) create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java create mode 100644 config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java create mode 100644 config/src/test/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigsTest.java create mode 100644 plugin/config/pom.xml create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeExecuteTypes.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangePointCutTypes.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeRequest.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java create mode 100644 plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java create mode 100644 plugin/config/src/test/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManagerTests.java diff --git a/config/pom.xml b/config/pom.xml index b42e163c2..00a8347f9 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -73,6 +73,11 @@ com.alibaba.nacos nacos-encryption-plugin + + + com.alibaba.nacos + nacos-config-plugin + org.apache.httpcomponents diff --git a/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java new file mode 100644 index 000000000..58be309b6 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java @@ -0,0 +1,398 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.aspect; + +import com.alibaba.nacos.api.config.remote.request.ConfigPublishRequest; +import com.alibaba.nacos.api.config.remote.request.ConfigRemoveRequest; +import com.alibaba.nacos.api.config.remote.response.ConfigPublishResponse; +import com.alibaba.nacos.api.config.remote.response.ConfigRemoveResponse; +import com.alibaba.nacos.api.remote.request.RequestMeta; +import com.alibaba.nacos.api.remote.response.ResponseCode; +import com.alibaba.nacos.common.model.RestResultUtils; +import com.alibaba.nacos.config.server.configuration.ConfigChangeConfigs; +import com.alibaba.nacos.config.server.model.SameConfigPolicy; +import com.alibaba.nacos.config.server.utils.ConfigExecutor; +import com.alibaba.nacos.config.server.utils.RequestUtil; +import com.alibaba.nacos.config.server.utils.TimeUtils; +import com.alibaba.nacos.plugin.config.ConfigChangePluginManager; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes; +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; +import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest; +import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse; +import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +/** + * Config change pointcut aspect,which config change plugin services will pointcut. + * + * @author liyunfei + */ +@Aspect +@Component +public class ConfigChangeAspect { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeAspect.class); + + private static final Integer DEFAULT_BEFORE_QUEUE_CAPACITY = 2; + + private static final Integer DEFAULT_AFTER_QUEUE_CAPACITY = 1; + + private static final String ENABLED = "enabled"; + + /** + * Publish or update config through http. + */ + private static final String CLIENT_INTERFACE_PUBLISH_CONFIG = + "execution(* com.alibaba.nacos.config.server.controller.ConfigController.publishConfig(..)) " + + "&& args(request,response,dataId,group,tenant,content,tag,appName,srcUser,configTags,desc,use,effect,type,..) " + + "&& @annotation(org.springframework.web.bind.annotation.PostMapping)"; + + /** + * Publish or update config through rpc. + */ + private static final String CLIENT_INTERFACE_PUBLISH_CONFIG_RPC = + "execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) " + + "&& target(com.alibaba.nacos.config.server.remote.ConfigPublishRequestHandler) " + + "&& args(request,meta)"; + + /** + * Remove config by id through http. + */ + private static final String CLIENT_INTERFACE_REMOVE_CONFIG = + "execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfig(..))" + + " && args(request,response,dataId,group,tenant,..)"; + + /** + * Remove config by ids through http. + */ + private static final String CLIENT_INTERFACE_BATCH_REMOVE_CONFIG = + "execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfigs(..))" + + " && args(request,ids)"; + + /** + * Remove config through rpc. + */ + @SuppressWarnings("checkstyle:linelength") + private static final String CLIENT_INTERFACE_REMOVE_CONFIG_RPC = + "execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) " + + " && target(com.alibaba.nacos.config.server.remote.ConfigRemoveRequestHandler)" + + " && args(request,meta)"; + + /** + * Import file through http. + */ + private static final String CLIENT_INTERFACE_IMPORT_CONFIG = + "execution(* com.alibaba.nacos.config.server.controller.ConfigController.importAndPublishConfig(..)) " + + "&& args(request,srcUser,namespace,policy,file)"; + + private final ConfigChangeConfigs configChangeConfigs; + + private ConfigChangePluginManager configChangeManager; + + public ConfigChangeAspect(ConfigChangeConfigs configChangeConfigs) { + this.configChangeConfigs = configChangeConfigs; + configChangeManager = ConfigChangePluginManager.getInstance(); + } + + /** + * Publish or update config. + */ + @Around(CLIENT_INTERFACE_PUBLISH_CONFIG) + Object publishOrUpdateConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request, + HttpServletResponse response, String dataId, String group, String tenant, String content, String tag, + String appName, String srcUser, String configTags, String desc, String use, String effect, String type) + throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_HTTP; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("dataId", dataId); + configChangeRequest.setArg("group", group); + configChangeRequest.setArg("tenant", tenant); + configChangeRequest.setArg("content", content); + configChangeRequest.setArg("tag", tag); + configChangeRequest.setArg("requestIpApp", appName); + configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request)); + configChangeRequest.setArg("configTags", configTags); + configChangeRequest.setArg("desc", desc); + configChangeRequest.setArg("use", use); + configChangeRequest.setArg("effect", effect); + configChangeRequest.setArg("type", type); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Remove config. + */ + @Around(CLIENT_INTERFACE_REMOVE_CONFIG) + Object removeConfigByIdAround(ProceedingJoinPoint pjp, HttpServletRequest request, HttpServletResponse response, + String dataId, String group, String tenant) throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_HTTP; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("dataId", dataId); + configChangeRequest.setArg("group", group); + configChangeRequest.setArg("tenant", tenant); + configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request)); + configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request)); + configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Remove config by ids. + */ + @Around(CLIENT_INTERFACE_BATCH_REMOVE_CONFIG) + public Object removeConfigByIdsAround(ProceedingJoinPoint pjp, HttpServletRequest request, List ids) + throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BATCH_HTTP; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("dataId", ids.toString()); + configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request)); + configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request)); + configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Import config. + */ + @Around(CLIENT_INTERFACE_IMPORT_CONFIG) + public Object importConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request, String srcUser, + String namespace, SameConfigPolicy policy, MultipartFile file) throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.IMPORT_BY_HTTP; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("srcUser", srcUser); + configChangeRequest.setArg("namespace", namespace); + configChangeRequest.setArg("policy", policy); + configChangeRequest.setArg("file", file); + configChangeRequest.setArg("srcIp", RequestUtil.getRemoteIp(request)); + configChangeRequest.setArg("requestIpApp", RequestUtil.getAppName(request)); + configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Publish or update config. + */ + @Around(CLIENT_INTERFACE_PUBLISH_CONFIG_RPC) + Object publishConfigAroundRpc(ProceedingJoinPoint pjp, ConfigPublishRequest request, RequestMeta meta) + throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_RPC; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("dataId", request.getDataId()); + configChangeRequest.setArg("group", request.getGroup()); + configChangeRequest.setArg("tenant", request.getTenant()); + configChangeRequest.setArg("content", request.getContent()); + configChangeRequest.setArg("type", request.getAdditionParam("type")); + configChangeRequest.setArg("tag", request.getAdditionParam("tag")); + configChangeRequest.setArg("configTags", request.getAdditionParam("config_tags")); + configChangeRequest.setArg("desc", request.getAdditionParam("desc")); + configChangeRequest.setArg("effect", request.getAdditionParam("effect")); + configChangeRequest.setArg("appName", request.getAdditionParam("appName")); + configChangeRequest.setArg("srcIp", meta.getClientIp()); + configChangeRequest.setArg("requestIpApp", request.getAdditionParam("requestIpApp")); + configChangeRequest.setArg("srcUser", request.getAdditionParam("src_user")); + configChangeRequest.setArg("use", request.getAdditionParam("use")); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Remove config. + */ + @Around(CLIENT_INTERFACE_REMOVE_CONFIG_RPC) + Object removeConfigAroundRpc(ProceedingJoinPoint pjp, ConfigRemoveRequest request, RequestMeta meta) + throws Throwable { + final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_RPC; + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + // didn't enabled or add relative plugin + if (pluginServicePriorityQueue.isEmpty()) { + return pjp.proceed(); + } + ConfigChangeRequest configChangeRequest = new ConfigChangeRequest(configChangePointCutType); + configChangeRequest.setArg("dataId", request.getDataId()); + configChangeRequest.setArg("group", request.getGroup()); + configChangeRequest.setArg("tenant", request.getTenant()); + configChangeRequest.setArg("appName", request.getHeader("appName")); + configChangeRequest.setArg("srcIp", meta.getClientIp()); + configChangeRequest.setArg("requestIpApp", request.getHeader("requestIpApp")); + configChangeRequest.setArg("srcUser", request.getHeader("src_user")); + configChangeRequest.setArg("use", request.getHeader("use")); + return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); + } + + /** + * Execute relevant config change plugin services. + */ + private Object configChangeServiceHandle(ProceedingJoinPoint pjp, + PriorityQueue configChangePluginServicePriorityQueue, + ConfigChangeRequest configChangeRequest) { + configChangeRequest.setArg("modifyTime", TimeUtils.getCurrentTimeStr()); + ConfigChangePointCutTypes handleType = configChangeRequest.getRequestType(); + ConfigChangeResponse configChangeResponse = new ConfigChangeResponse(handleType); + configChangeResponse.setSuccess(true); // default success,when before plugin service verify failed , set false + PriorityQueue beforeExecutePriorityQueue = new PriorityQueue<>( + DEFAULT_BEFORE_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); + PriorityQueue afterExecutePriorityQueue = new PriorityQueue<>( + DEFAULT_AFTER_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); + + Object retVal = null; + Object[] args = pjp.getArgs(); + + for (ConfigChangePluginService ccs : configChangePluginServicePriorityQueue) { + if (!isEnabled(ccs)) { + continue; + } + if (ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE.equals(ccs.executeType())) { + beforeExecutePriorityQueue.add(ccs); + } else { + afterExecutePriorityQueue.add(ccs); + } + final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT); + final Properties properties = configChangeConfigs.getPluginProperties(serviceType); + // set server config relative info to plugin + switch (serviceType) { + case "webhook": { + configChangeRequest.setArg("webhookUrl", properties.getProperty("url")); + configChangeRequest.setArg("contentMaxCapacity", properties.getProperty("contentMaxCapacity")); + break; + } + case "whitelist": { + configChangeRequest.setArg("suffixs", properties.getProperty("suffixs")); + configChangeRequest.setArg("args", args); + break; + } + default: { + // ignore + } + } + } + + // before plugin service execute + for (ConfigChangePluginService ccs : beforeExecutePriorityQueue) { + ccs.execute(configChangeRequest, configChangeResponse); + if (ccs.getServiceType().equals("whitelist")) { + args = (Object[]) configChangeRequest.getArg("args"); // update args by filter with witelist + } + // prevent execute next before plugins service + if (!configChangeResponse.isSuccess()) { + retVal = wrapErrorResp(configChangeResponse); + break; + } + } + + try { + if (configChangeResponse.isSuccess()) { // if validate failed,skipped directly + retVal = pjp.proceed(args); + } + } catch (Throwable e) { + LOGGER.warn("config change plugin proceed failed {}", e.getMessage()); + configChangeResponse.setMsg("config change plugin proceed failed " + e.getMessage()); + retVal = wrapErrorResp(configChangeResponse); + } + + // after plugin service execute + ConfigExecutor.executeAsyncConfigChangePluginTask(() -> { + for (ConfigChangePluginService ccs : afterExecutePriorityQueue) { + try { + ccs.execute(configChangeRequest, configChangeResponse); + } catch (Throwable throwable) { + LOGGER.warn("execute async plugin services failed {}", throwable.getMessage()); + } + } + }); + + return retVal; + } + + private PriorityQueue getPluginServicePriorityQueue(ConfigChangePointCutTypes configChangePointCutType) { + PriorityQueue pluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(configChangePointCutType); + if (pluginServicePriorityQueue == null) { + return new PriorityQueue<>(); + } + for (ConfigChangePluginService each : pluginServicePriorityQueue) { + if (isEnabled(each)) { + return pluginServicePriorityQueue; + } + } + return new PriorityQueue<>(); + } + + private boolean isEnabled(ConfigChangePluginService configChangePluginService) { + Properties serviceConfigProperties = configChangeConfigs.getPluginProperties(configChangePluginService.getServiceType()); + return Boolean.parseBoolean(serviceConfigProperties.getProperty(ENABLED)); + } + + private Object wrapErrorResp(ConfigChangeResponse configChangeResponse) { + Object retVal = null; + switch (configChangeResponse.getResponseType()) { + // some of controller did'nt design error msg resp + case IMPORT_BY_HTTP: + case REMOVE_BATCH_HTTP: + case REMOVE_BY_HTTP: + case PUBLISH_BY_HTTP: { + retVal = RestResultUtils.failed(configChangeResponse.getMsg()); + break; + } + case PUBLISH_BY_RPC: { + retVal = ConfigPublishResponse.buildFailResponse(ResponseCode.FAIL.getCode(), configChangeResponse.getMsg()); + break; + } + case REMOVE_BY_RPC: { + retVal = ConfigRemoveResponse.buildFailResponse(configChangeResponse.getMsg()); + break; + } + default: { + // ignore + } + } + return retVal; + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java new file mode 100644 index 000000000..870be5950 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java @@ -0,0 +1,166 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.configuration; + +import com.alibaba.nacos.common.event.ServerConfigChangeEvent; +import com.alibaba.nacos.common.notify.Event; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.notify.listener.Subscriber; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; +import com.alibaba.nacos.sys.env.EnvUtil; +import com.alibaba.nacos.sys.utils.PropertiesUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * config change plugin configs. + * + * @author liyunfei + **/ +@Configuration +public class ConfigChangeConfigs extends Subscriber { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConfigs.class); + + private static final String PREFIX = ConfigChangeConstants.NACOS_CORE_CONFIG_PLUGIN_PREFIX; + + /** + * Whether webhook config change plugin enabled. + */ + @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED + ":false}") + private boolean webhookEnabled; + + /** + * The url which webhook. + */ + @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL + ":}") + private String webhookUrl; + + /** + * The max content capacity which webhook push. + */ + @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY + ":102400}") + private int webhookContentMaxCapacity; + + /** + * Whether whitelist config change plugin enabled. + */ + @Value("${" + ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED + ":false}") + private boolean whiteListEnabled; + + /** + * Whether whitelist sets. + */ + @Value("${" + ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS + ":}") + private String whiteListSuffixs; + + /** + * Whether file format config change plugin enabled. + */ + @Value("${" + ConfigChangeConstants.FileFormatCheck.NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED + ":false}") + private boolean fileFormatCheckEnabled; + + private Map configPluginProperties = new HashMap<>(); + + public ConfigChangeConfigs() { + NotifyCenter.registerSubscriber(this); + refreshPluginProperties(); + } + + public boolean isWebHookEnabled() { + return webhookEnabled; + } + + public String getWebHookUrl() { + return webhookUrl; + } + + public int getWebHookMaxContentCapacity() { + // default 100kb + return webhookContentMaxCapacity; + } + + public boolean isWhiteListEnabled() { + return whiteListEnabled; + } + + public String getWhiteListSuffixs() { + return whiteListSuffixs; + } + + public boolean isFileFormatCheckEnabled() { + return whiteListEnabled; + } + + private void refreshPluginProperties() { + try { + Map newProperties = new HashMap<>(3); + Properties properties = PropertiesUtil.getPropertiesWithPrefix(EnvUtil.getEnvironment(), PREFIX); + for (String each : properties.stringPropertyNames()) { + int typeIndex = each.indexOf('.'); + String type = each.substring(0, typeIndex); + String subKey = each.substring(typeIndex + 1); + newProperties.computeIfAbsent(type, key -> new Properties()) + .setProperty(subKey, properties.getProperty(each)); + } + configPluginProperties = newProperties; + } catch (Exception e) { + LOGGER.warn("[ConfigChangeConfigs]Refresh config plugin properties failed ", e); + } + } + + public Properties getPluginProperties(String configPluginType) { + if (!configPluginProperties.containsKey(configPluginType)) { + LOGGER.warn("[ConfigChangeConfigs]Can't find config plugin properties for type {}, will use empty properties", configPluginType); + return new Properties(); + } + return configPluginProperties.get(configPluginType); + } + + @Override + public void onEvent(ServerConfigChangeEvent event) { + try { + webhookEnabled = EnvUtil.getProperty(ConfigChangeConstants.Webhook + .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED, Boolean.class); + webhookUrl = EnvUtil.getProperty(ConfigChangeConstants.Webhook + .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL, String.class); + webhookContentMaxCapacity = EnvUtil.getProperty(ConfigChangeConstants.Webhook + .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY, Integer.class); + whiteListEnabled = EnvUtil.getProperty(ConfigChangeConstants.WhiteList + .NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED, Boolean.class); + whiteListSuffixs = EnvUtil.getProperty(ConfigChangeConstants.WhiteList + .NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS, String.class); + fileFormatCheckEnabled = EnvUtil.getProperty(ConfigChangeConstants.FileFormatCheck + .NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED, Boolean.class); + LOGGER.info("[ConfigChangeConfigs]Upgrade config change plugin configs successfully, {} enabled:{} , {} enabled:{}, {} enbaled: {}", + "webhook", isWebHookEnabled(), "fileformatcheck", isFileFormatCheckEnabled(), "whitelist", isWhiteListEnabled()); + } catch (Exception e) { + LOGGER.warn("[ConfigChangeConfigs]Upgrade config change plugin config from env failed, use old value", e); + } + } + + @Override + public Class subscribeType() { + return ServerConfigChangeEvent.class; + } +} diff --git a/config/src/main/java/com/alibaba/nacos/config/server/utils/ConfigExecutor.java b/config/src/main/java/com/alibaba/nacos/config/server/utils/ConfigExecutor.java index 1418725b5..6b5daeebd 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/utils/ConfigExecutor.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/utils/ConfigExecutor.java @@ -50,7 +50,12 @@ public final class ConfigExecutor { private static final ScheduledExecutorService ASYNC_NOTIFY_EXECUTOR = ExecutorFactory.Managed .newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class), 100, new NameThreadFactory("com.alibaba.nacos.config.AsyncNotifyService")); - + + private static final ScheduledExecutorService ASYNC_CONFIG_CHANGE_PLUGIN_EXECUTOR = ExecutorFactory.Managed + .newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class), + ThreadUtils.getSuitableThreadCount(), + new NameThreadFactory("com.alibaba.nacos.config.plugin.AsyncService")); + private static final ScheduledExecutorService CONFIG_SUB_SERVICE_EXECUTOR = ExecutorFactory.Managed .newScheduledExecutorService(ClassUtils.getCanonicalName(Config.class), ThreadUtils.getSuitableThreadCount(), @@ -84,7 +89,11 @@ public final class ConfigExecutor { public static void scheduleAsyncNotify(Runnable command, long delay, TimeUnit unit) { ASYNC_NOTIFY_EXECUTOR.schedule(command, delay, unit); } - + + public static void executeAsyncConfigChangePluginTask(Runnable runnable) { + ASYNC_CONFIG_CHANGE_PLUGIN_EXECUTOR.execute(runnable); + } + public static int asyncNotifyQueueSize() { return ((ScheduledThreadPoolExecutor) ASYNC_NOTIFY_EXECUTOR).getQueue().size(); } diff --git a/config/src/test/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigsTest.java b/config/src/test/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigsTest.java new file mode 100644 index 000000000..ff7757b7c --- /dev/null +++ b/config/src/test/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigsTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.configuration; + +import com.alibaba.nacos.common.event.ServerConfigChangeEvent; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.env.MockEnvironment; + +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +public class ConfigChangeConfigsTest { + + private static final boolean TEST_WEBHOOK_ENABLED = false; + + private static final String TEST_WEBHOOK_URL = "http://localhost:8080/webhook/putEvent?token=***"; + + private static final int TEST_WEBHOOK_CONTENT_MAX_CAPACITY = 10 * 1024; + + private static final boolean TEST_FILEFORMATCHECK_ENABLED = false; + + private static final boolean TEST_WHITELIST_ENABLED = false; + + private static final String TEST_WEBHOOK_SUFFIXS = "text,yaml,html"; + + private ConfigChangeConfigs configChangeConfigs; + + private MockEnvironment environment; + + @Before + public void setUp() throws Exception { + environment = new MockEnvironment(); + EnvUtil.setEnvironment(environment); + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED, "true"); + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL, "http://sample.com/webhook"); + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY, "10240"); + environment.setProperty(ConfigChangeConstants.FileFormatCheck.NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED, "true"); + environment.setProperty(ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED, "true"); + environment.setProperty(ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS, "yaml,xml"); + configChangeConfigs = new ConfigChangeConfigs(); + } + + @Test + public void testUpgradeFromEvent() { + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED, + String.valueOf(TEST_WEBHOOK_ENABLED)); + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL, + TEST_WEBHOOK_URL); + environment.setProperty(ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY, + String.valueOf(TEST_WEBHOOK_CONTENT_MAX_CAPACITY)); + environment.setProperty(ConfigChangeConstants.FileFormatCheck.NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED, + String.valueOf(TEST_FILEFORMATCHECK_ENABLED)); + environment.setProperty(ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED, + String.valueOf(TEST_WHITELIST_ENABLED)); + environment.setProperty(ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS, + TEST_WEBHOOK_SUFFIXS); + + configChangeConfigs.onEvent(ServerConfigChangeEvent.newEvent()); + assertEquals(TEST_WEBHOOK_ENABLED, configChangeConfigs.isWebHookEnabled()); + assertEquals(TEST_WEBHOOK_URL, configChangeConfigs.getWebHookUrl()); + assertEquals(TEST_WEBHOOK_CONTENT_MAX_CAPACITY, configChangeConfigs.getWebHookMaxContentCapacity()); + assertEquals(TEST_WHITELIST_ENABLED, configChangeConfigs.isWhiteListEnabled()); + assertEquals(TEST_WEBHOOK_SUFFIXS, configChangeConfigs.getWhiteListSuffixs()); + assertEquals(TEST_FILEFORMATCHECK_ENABLED, configChangeConfigs.isFileFormatCheckEnabled()); + } + + @Test + public void testGetPropertiesByType() { + configChangeConfigs.onEvent(ServerConfigChangeEvent.newEvent()); + String configPluginServiceType = "webhook"; + Properties properties = configChangeConfigs.getPluginProperties(configPluginServiceType); + assertEquals(configChangeConfigs.isWebHookEnabled(), Boolean.valueOf(properties.getProperty("enabled"))); + configPluginServiceType = "fileformatcheck"; + properties = configChangeConfigs.getPluginProperties(configPluginServiceType); + assertEquals(configChangeConfigs.isFileFormatCheckEnabled(), Boolean.valueOf(properties.getProperty("enabled"))); + configPluginServiceType = "whitelist"; + properties = configChangeConfigs.getPluginProperties(configPluginServiceType); + assertEquals(configChangeConfigs.isWhiteListEnabled(), Boolean.valueOf(properties.getProperty("enabled"))); + } +} diff --git a/console/src/main/resources/application.properties b/console/src/main/resources/application.properties index 79e704af5..bba509c47 100644 --- a/console/src/main/resources/application.properties +++ b/console/src/main/resources/application.properties @@ -139,6 +139,19 @@ nacos.core.auth.plugin.nacos.token.secret.key=SecretKey0123456789012345678901234 #nacos.core.auth.ldap.filter.prefix=uid #nacos.core.auth.ldap.case.sensitive=true +#*************** Config Change Plugin Related Configurations ***************# +# webhook +nacos.core.config.plugin.webhook.enabled=false +# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html +nacos.core.config.plugin.webhook.url=http://localhost:8080/webhook/send?token=*** +# The content push max capacity ,byte +nacos.core.config.plugin.webhook.contentMaxCapacity=102400 +# whitelist +nacos.core.config.plugin.whitelist.enabled=false +# The import file suffixs +nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html +# fileformatcheck,which validate the import file of type and content +nacos.core.config.plugin.fileformatcheck.enabled=false #*************** Istio Related Configurations ***************# ### If turn on the MCP server: diff --git a/plugin/config/pom.xml b/plugin/config/pom.xml new file mode 100644 index 000000000..a68c199e0 --- /dev/null +++ b/plugin/config/pom.xml @@ -0,0 +1,40 @@ + + + + + + nacos-plugin + com.alibaba.nacos + ${revision} + + 4.0.0 + + nacos-config-plugin + nacos-config-plugin ${project.version} + http://nacos.io + + + + com.alibaba.nacos + nacos-common + provided + + + + \ No newline at end of file diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java new file mode 100644 index 000000000..294ce6787 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java @@ -0,0 +1,137 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config; + +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; +import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Collection; +import java.util.PriorityQueue; +import java.util.Optional; +import java.util.Comparator; +import java.util.concurrent.ConcurrentHashMap; + +/** + * All config change plugin manager. + * + * @author liyunfei + */ +public class ConfigChangePluginManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangePluginManager.class); + + private static final Integer PLUGIN_SERVICE_COUNT = ConfigChangeConstants.getPluginServiceCount(); + + private static final Integer POINT_CUT_TYPE_COUNT = ConfigChangePointCutTypes.values().length; + + /** + * The relationship of serviceType and {@link ConfigChangePluginService} ,default capacity is the count of plugin + * service. + */ + private static Map configChangeServiceMap = new ConcurrentHashMap<>( + PLUGIN_SERVICE_COUNT); + + /** + * The relationship of config change pointcut type and the queue of {@link ConfigChangePluginService} will pointcut it, + * default capacity is the count of pointcutTypes. + */ + private static Map> priorityQueueMap = new ConcurrentHashMap<>( + POINT_CUT_TYPE_COUNT); + + private static final ConfigChangePluginManager INSTANCE = new ConfigChangePluginManager(); + + private ConfigChangePluginManager() { + loadConfigChangeServices(); + } + + /** + * Load all config change plugin services by spi. + */ + private static void loadConfigChangeServices() { + Collection configChangePluginServices = NacosServiceLoader.load(ConfigChangePluginService.class); + // load all config change plugin by spi + for (ConfigChangePluginService each : configChangePluginServices) { + if (StringUtils.isEmpty(each.getServiceType())) { + LOGGER.warn("[ConfigChangePluginManager] Load {}({}) ConfigChangeServiceName(null/empty) fail. " + + "Please Add the Plugin Service ConfigChangeServiceName to resolve.", + each.getClass().getName(), each.getClass()); + continue; + } + configChangeServiceMap.put(each.getServiceType(), each); + LOGGER.info("[ConfigChangePluginManager] Load {}({}) ConfigChangeServiceName({}) successfully.", + each.getClass().getName(), each.getClass(), each.getServiceType()); + // map the relationship of pointcut and plugin service + addPluginServiceByPointCut(each); + } + } + + public static ConfigChangePluginManager getInstance() { + return INSTANCE; + } + + /** + * Dynamic get any pluginServiceImpl. + * + * @param serviceType plugin service type. + * @return + */ + public Optional findPluginServiceImpl(String serviceType) { + return Optional.ofNullable(configChangeServiceMap.get(serviceType)); + } + + /** + * Dynamic add new ConfigChangeService. + * + * @param configChangePluginService ConfigChangeService. + * @return + */ + public static synchronized boolean join(ConfigChangePluginService configChangePluginService) { + configChangeServiceMap.putIfAbsent(configChangePluginService.getServiceType(), configChangePluginService); + addPluginServiceByPointCut(configChangePluginService); + return true; + } + + /** + * Get the plugin service queue of the pointcut method. + * + * @param pointcutName pointcut method name,detail see {@link ConfigChangePointCutTypes}. + * @return + */ + public static PriorityQueue findPluginServiceQueueByPointcut(ConfigChangePointCutTypes pointcutName) { + return priorityQueueMap.getOrDefault(pointcutName, new PriorityQueue<>()); + } + + private static boolean addPluginServiceByPointCut(ConfigChangePluginService configChangePluginService) { + ConfigChangePointCutTypes[] pointcutNames = configChangePluginService.pointcutMethodNames(); + for (ConfigChangePointCutTypes name : pointcutNames) { + PriorityQueue configChangePluginServicePriorityQueue = priorityQueueMap.get(name); + if (configChangePluginServicePriorityQueue == null) { + configChangePluginServicePriorityQueue = new PriorityQueue<>(PLUGIN_SERVICE_COUNT, + Comparator.comparingInt(ConfigChangePluginService::getOrder)); + } + configChangePluginServicePriorityQueue.add(configChangePluginService); + priorityQueueMap.put(name, configChangePluginServicePriorityQueue); + } + return true; + } +} diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java new file mode 100644 index 000000000..d7e64b832 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.constants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Config change plugin service constants. + * + * @author liyunfei + */ +public class ConfigChangeConstants { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConstants.class); + + /** + * The relationship of config change plugin service name and its pointcuts. + */ + private static final Map POINTCUTS_MAP = new ConcurrentHashMap(); + + public static final String NACOS_CORE_CONFIG_PLUGIN_PREFIX = "nacos.core.config.plugin."; + + public static final String POINT_CUT_NAME = "CONFIG_CHANGE_POINT_CUT_TYPES_TYPES"; + + private static Integer pluginServiceCount = 0; + + /** + * Webhook plugin service relevant server configs. + */ + public static class Webhook { + + /** + * The plugin service will execute when the action produce. + */ + public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = ConfigChangePointCutTypes + .values(); + + public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED = "nacos.core.config.plugin.webhook.enabled"; + + public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL = "nacos.core.config.plugin.webhook.url"; + + public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY = "nacos.core.config.plugin.webhook.contentMaxCapacity"; + } + + /** + * File format check plugin service relevant server configs. + */ + public static class FileFormatCheck { + + /** + * The plugin service will execute when the action produce. + */ + public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = { + ConfigChangePointCutTypes.PUBLISH_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC}; + + public static final String NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED = "nacos.core.config.plugin.fileformatcheck.enabled"; + + } + + /** + * WhiteList plugin service relevant server configs. + */ + public static class WhiteList { + + /** + * The plugin service will execute when the action produce. + */ + public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = { + ConfigChangePointCutTypes.IMPORT_BY_HTTP}; + + public static final String NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED = "nacos.core.config.plugin.whitelist.enabled"; + + public static final String NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS = "nacos.core.config.plugin.whitelist.suffixs"; + + } + + // Load config pointcuts to each config change plugin services. + static { + Class[] innerClasses = ConfigChangeConstants.class.getDeclaredClasses(); + for (Class clazz : innerClasses) { + try { + POINTCUTS_MAP.put(clazz.getSimpleName().toLowerCase(Locale.ROOT), + (ConfigChangePointCutTypes[]) clazz.getField(POINT_CUT_NAME).get(null)); + pluginServiceCount++; + } catch (NoSuchFieldException | IllegalAccessException e) { + LOGGER.warn( + "[{}] Load config change plugin service to relevant pointcuts failed,please check {} at {} ", + ConfigChangeConstants.class, POINT_CUT_NAME, clazz); + } + } + } + + public static ConfigChangePointCutTypes[] getPointcuts(String serviceType) { + return POINTCUTS_MAP.get(serviceType); + } + + public static Integer getPluginServiceCount() { + return pluginServiceCount; + } +} + diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeExecuteTypes.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeExecuteTypes.java new file mode 100644 index 000000000..afed7b87a --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeExecuteTypes.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.constants; + +/** + * ConfigChangeExecuteTypes. + * + * @author liyunfei + */ +public enum ConfigChangeExecuteTypes { + /** + * Execute before pointcut. + */ + EXECUTE_BEFORE_TYPE, + /** + * Execute after pointcut. + */ + EXECUTE_AFTER_TYPE; + + public boolean equals(ConfigChangeExecuteTypes configChangeExecuteTypes) { + return this.compareTo(configChangeExecuteTypes) == 0; + } +} diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangePointCutTypes.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangePointCutTypes.java new file mode 100644 index 000000000..5bf614c09 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangePointCutTypes.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.constants; + +/** + * Config change type depend on the pointcut method. + * + * @author liyunfei + */ +public enum ConfigChangePointCutTypes { + + /** + * Publish or update config through http. + */ + PUBLISH_BY_HTTP("publishOrUpdateByHttp"), + /** + * Publish config through rpc. + */ + PUBLISH_BY_RPC("publishOrUpdateByRpc"), + /** + * Remove by id through http. + */ + REMOVE_BY_HTTP("removeSingleByHttp"), + /** + * Remove through rpc. + */ + REMOVE_BY_RPC("removeSingleByRpc"), + /** + * Import config file through http/console. + */ + IMPORT_BY_HTTP("importFileByHttp"), + /** + * Remove by ids through http. + */ + REMOVE_BATCH_HTTP("removeBatchByHttp"); + + private final String value; + + ConfigChangePointCutTypes(String value) { + this.value = value; + } + + public String value() { + return value; + } + + public boolean equals(ConfigChangePointCutTypes configChangePointCutTypes) { + return this.compareTo(configChangePointCutTypes) == 0; + } +} diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeRequest.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeRequest.java new file mode 100644 index 000000000..e8467fc58 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeRequest.java @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.model; + +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; + +import java.util.HashMap; + +/** + * ConfigChangeRequest. + * + * @author liyunfei + */ +public class ConfigChangeRequest { + + private ConfigChangePointCutTypes requestType; + + private HashMap requestArgs = new HashMap<>(8); + + public ConfigChangeRequest(ConfigChangePointCutTypes requestType) { + this.requestType = requestType; + } + + public ConfigChangePointCutTypes getRequestType() { + return requestType; + } + + public void setArg(String key, Object value) { + requestArgs.putIfAbsent(key, value); + } + + public Object getArg(String key) { + return requestArgs.getOrDefault(key, null); + } + + public HashMap getRequestArgs() { + return requestArgs; + } +} diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java new file mode 100644 index 000000000..42c0f9af7 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.model; + +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; + +/** + * ConfigChangeResponse. + * + * @author liyunfei + */ +public class ConfigChangeResponse { + + private ConfigChangePointCutTypes responseType; + + private boolean isSuccess; + + private Object retVal; + + private String msg; + + public ConfigChangeResponse(ConfigChangePointCutTypes responseType) { + this.responseType = responseType; + } + + public ConfigChangePointCutTypes getResponseType() { + return responseType; + } + + public void setResponseType(ConfigChangePointCutTypes responseType) { + this.responseType = responseType; + } + + public boolean isSuccess() { + return isSuccess; + } + + public void setSuccess(boolean success) { + isSuccess = success; + } + + public Object getRetVal() { + return retVal; + } + + public void setRetVal(Object retVal) { + this.retVal = retVal; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java new file mode 100644 index 000000000..bb9afdb94 --- /dev/null +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config.spi; + +import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes; +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; +import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest; +import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse; + +/** + * ConfigChangePluginService. + * + * @author liyunfei + */ +public interface ConfigChangePluginService { + + /** + * execute config change plugin service. + * + * @param configChangeRequest ConfigChangeRequest + * @param configChangeResponse ConfigChangeResponse + */ + void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse); + + /** + * execute type {@link ConfigChangeExecuteTypes}. + * + * @return type + */ + ConfigChangeExecuteTypes executeType(); + + + /** + * what kind of plugin service,such as webhook,whiteList and other,need keep a way with the constants config of you + * enum in {@link ConfigChangeConstants}. + * + * @return service type + */ + String getServiceType(); + + /** + * when pointcut the same method,according to order to load plugin service. order is lower,prior is higher. + * + * @return order + */ + int getOrder(); + + /** + * the ConfigChangeTypes {@link ConfigChangePointCutTypes} of need to pointcut. + * + *

+ * ConfigChangeTypes mean the relevant pointcut method. + *

+ * + * @return array of pointcut the methods + */ + default ConfigChangePointCutTypes[] pointcutMethodNames() { + return ConfigChangeConstants.getPointcuts(getServiceType()); + } + +} diff --git a/plugin/config/src/test/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManagerTests.java b/plugin/config/src/test/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManagerTests.java new file mode 100644 index 000000000..12c39da45 --- /dev/null +++ b/plugin/config/src/test/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManagerTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 1999-2022 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.plugin.config; + +import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes; +import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; +import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest; +import com.alibaba.nacos.plugin.config.model.ConfigChangeResponse; +import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; +import java.util.PriorityQueue; + +/** + * ConfigChangePluginManagerTests. + * + * @author liyunfei + **/ +public class ConfigChangePluginManagerTests { + @Test + public void testInstance() { + ConfigChangePluginManager instance = ConfigChangePluginManager.getInstance(); + Assert.assertNotNull(instance); + } + + @Before + public void initPluginServices() { + ConfigChangePluginManager.join(new ConfigChangePluginService() { + @Override + public void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse) { + // ignore + } + + @Override + public ConfigChangeExecuteTypes executeType() { + return ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE; + } + + @Override + public String getServiceType() { + return "test1"; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public ConfigChangePointCutTypes[] pointcutMethodNames() { + return new ConfigChangePointCutTypes[]{ConfigChangePointCutTypes.PUBLISH_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC}; + } + }); + ConfigChangePluginManager.join(new ConfigChangePluginService() { + @Override + public void execute(ConfigChangeRequest configChangeRequest, ConfigChangeResponse configChangeResponse) { + // ignore + } + + @Override + public ConfigChangeExecuteTypes executeType() { + return ConfigChangeExecuteTypes.EXECUTE_BEFORE_TYPE; + } + + @Override + public String getServiceType() { + return "test2"; + } + + @Override + public int getOrder() { + return 200; + } + + @Override + public ConfigChangePointCutTypes[] pointcutMethodNames() { + return new ConfigChangePointCutTypes[]{ConfigChangePointCutTypes.IMPORT_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC}; + } + }); + } + + @Test + public void testFindPluginServiceQueueByPointcut() { + PriorityQueue configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.PUBLISH_BY_HTTP); + Assert.assertEquals(1, configChangePluginServicePriorityQueue.size()); + configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.PUBLISH_BY_RPC); + Assert.assertEquals(2, configChangePluginServicePriorityQueue.size()); + configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.IMPORT_BY_HTTP); + Assert.assertEquals(1, configChangePluginServicePriorityQueue.size()); + configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BATCH_HTTP); + Assert.assertEquals(0, configChangePluginServicePriorityQueue.size()); + configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BY_RPC); + Assert.assertEquals(0, configChangePluginServicePriorityQueue.size()); + configChangePluginServicePriorityQueue = ConfigChangePluginManager + .findPluginServiceQueueByPointcut(ConfigChangePointCutTypes.REMOVE_BY_HTTP); + Assert.assertEquals(0, configChangePluginServicePriorityQueue.size()); + } + + @Test + public void testFindPluginServiceByServiceType() { + Optional configChangePluginServiceOptional = ConfigChangePluginManager + .getInstance().findPluginServiceImpl("test1"); + Assert.assertTrue(configChangePluginServiceOptional.isPresent()); + configChangePluginServiceOptional = ConfigChangePluginManager.getInstance().findPluginServiceImpl("test2"); + Assert.assertTrue(configChangePluginServiceOptional.isPresent()); + configChangePluginServiceOptional = ConfigChangePluginManager.getInstance().findPluginServiceImpl("test3"); + Assert.assertFalse(configChangePluginServiceOptional.isPresent()); + } +} diff --git a/plugin/pom.xml b/plugin/pom.xml index 3852ad1c4..f98f224f7 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -36,6 +36,7 @@ datasource environment control + config pom diff --git a/pom.xml b/pom.xml index 9c4368994..eec4aa06e 100644 --- a/pom.xml +++ b/pom.xml @@ -720,6 +720,11 @@ nacos-encryption-plugin ${project.version}
+ + com.alibaba.nacos + nacos-config-plugin + ${project.version} + ${project.groupId} nacos-control-plugin From 23780d9b157a97ca485d4c39a1e921e1f1e6ef78 Mon Sep 17 00:00:00 2001 From: KomachiSion Date: Thu, 11 May 2023 16:44:29 +0800 Subject: [PATCH 2/5] =?UTF-8?q?ConfigChangeAspect=20=E5=8E=BB=E9=99=A4?= =?UTF-8?q?=E5=AF=B9=E6=8F=92=E4=BB=B6=E5=AE=9E=E7=8E=B0=E7=9A=84=E6=84=9F?= =?UTF-8?q?=E7=9F=A5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/aspect/ConfigChangeAspect.java | 137 +++++++++--------- .../constants/ConfigChangeConstants.java | 7 + .../config/model/ConfigChangeResponse.java | 11 +- 3 files changed, 87 insertions(+), 68 deletions(-) diff --git a/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java index 58be309b6..2c8c95935 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java @@ -29,6 +29,7 @@ import com.alibaba.nacos.config.server.utils.ConfigExecutor; import com.alibaba.nacos.config.server.utils.RequestUtil; import com.alibaba.nacos.config.server.utils.TimeUtils; import com.alibaba.nacos.plugin.config.ConfigChangePluginManager; +import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; import com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes; import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; import com.alibaba.nacos.plugin.config.model.ConfigChangeRequest; @@ -44,7 +45,11 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.*; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.PriorityQueue; +import java.util.Properties; /** * Config change pointcut aspect,which config change plugin services will pointcut. @@ -54,15 +59,15 @@ import java.util.*; @Aspect @Component public class ConfigChangeAspect { - + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeAspect.class); - + private static final Integer DEFAULT_BEFORE_QUEUE_CAPACITY = 2; - + private static final Integer DEFAULT_AFTER_QUEUE_CAPACITY = 1; - + private static final String ENABLED = "enabled"; - + /** * Publish or update config through http. */ @@ -70,7 +75,7 @@ public class ConfigChangeAspect { "execution(* com.alibaba.nacos.config.server.controller.ConfigController.publishConfig(..)) " + "&& args(request,response,dataId,group,tenant,content,tag,appName,srcUser,configTags,desc,use,effect,type,..) " + "&& @annotation(org.springframework.web.bind.annotation.PostMapping)"; - + /** * Publish or update config through rpc. */ @@ -78,21 +83,21 @@ public class ConfigChangeAspect { "execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) " + "&& target(com.alibaba.nacos.config.server.remote.ConfigPublishRequestHandler) " + "&& args(request,meta)"; - + /** * Remove config by id through http. */ private static final String CLIENT_INTERFACE_REMOVE_CONFIG = "execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfig(..))" + " && args(request,response,dataId,group,tenant,..)"; - + /** * Remove config by ids through http. */ private static final String CLIENT_INTERFACE_BATCH_REMOVE_CONFIG = "execution(* com.alibaba.nacos.config.server.controller.ConfigController.deleteConfigs(..))" + " && args(request,ids)"; - + /** * Remove config through rpc. */ @@ -101,33 +106,34 @@ public class ConfigChangeAspect { "execution(* com.alibaba.nacos.core.remote.RequestHandler.handleRequest(..)) " + " && target(com.alibaba.nacos.config.server.remote.ConfigRemoveRequestHandler)" + " && args(request,meta)"; - + /** * Import file through http. */ private static final String CLIENT_INTERFACE_IMPORT_CONFIG = "execution(* com.alibaba.nacos.config.server.controller.ConfigController.importAndPublishConfig(..)) " + "&& args(request,srcUser,namespace,policy,file)"; - + private final ConfigChangeConfigs configChangeConfigs; - + private ConfigChangePluginManager configChangeManager; - + public ConfigChangeAspect(ConfigChangeConfigs configChangeConfigs) { this.configChangeConfigs = configChangeConfigs; configChangeManager = ConfigChangePluginManager.getInstance(); } - + /** * Publish or update config. */ @Around(CLIENT_INTERFACE_PUBLISH_CONFIG) Object publishOrUpdateConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request, - HttpServletResponse response, String dataId, String group, String tenant, String content, String tag, - String appName, String srcUser, String configTags, String desc, String use, String effect, String type) + HttpServletResponse response, String dataId, String group, String tenant, String content, String tag, + String appName, String srcUser, String configTags, String desc, String use, String effect, String type) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_HTTP; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -147,15 +153,16 @@ public class ConfigChangeAspect { configChangeRequest.setArg("type", type); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Remove config. */ @Around(CLIENT_INTERFACE_REMOVE_CONFIG) Object removeConfigByIdAround(ProceedingJoinPoint pjp, HttpServletRequest request, HttpServletResponse response, - String dataId, String group, String tenant) throws Throwable { + String dataId, String group, String tenant) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_HTTP; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -169,7 +176,7 @@ public class ConfigChangeAspect { configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Remove config by ids. */ @@ -177,7 +184,8 @@ public class ConfigChangeAspect { public Object removeConfigByIdsAround(ProceedingJoinPoint pjp, HttpServletRequest request, List ids) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BATCH_HTTP; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -189,15 +197,16 @@ public class ConfigChangeAspect { configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Import config. */ @Around(CLIENT_INTERFACE_IMPORT_CONFIG) public Object importConfigAround(ProceedingJoinPoint pjp, HttpServletRequest request, String srcUser, - String namespace, SameConfigPolicy policy, MultipartFile file) throws Throwable { + String namespace, SameConfigPolicy policy, MultipartFile file) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.IMPORT_BY_HTTP; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -212,7 +221,7 @@ public class ConfigChangeAspect { configChangeRequest.setArg("use", RequestUtil.getSrcUserName(request)); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Publish or update config. */ @@ -220,7 +229,8 @@ public class ConfigChangeAspect { Object publishConfigAroundRpc(ProceedingJoinPoint pjp, ConfigPublishRequest request, RequestMeta meta) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.PUBLISH_BY_RPC; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -242,7 +252,7 @@ public class ConfigChangeAspect { configChangeRequest.setArg("use", request.getAdditionParam("use")); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Remove config. */ @@ -250,7 +260,8 @@ public class ConfigChangeAspect { Object removeConfigAroundRpc(ProceedingJoinPoint pjp, ConfigRemoveRequest request, RequestMeta meta) throws Throwable { final ConfigChangePointCutTypes configChangePointCutType = ConfigChangePointCutTypes.REMOVE_BY_RPC; - final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue(configChangePointCutType); + final PriorityQueue pluginServicePriorityQueue = getPluginServicePriorityQueue( + configChangePointCutType); // didn't enabled or add relative plugin if (pluginServicePriorityQueue.isEmpty()) { return pjp.proceed(); @@ -266,25 +277,26 @@ public class ConfigChangeAspect { configChangeRequest.setArg("use", request.getHeader("use")); return configChangeServiceHandle(pjp, pluginServicePriorityQueue, configChangeRequest); } - + /** * Execute relevant config change plugin services. */ private Object configChangeServiceHandle(ProceedingJoinPoint pjp, - PriorityQueue configChangePluginServicePriorityQueue, - ConfigChangeRequest configChangeRequest) { + PriorityQueue configChangePluginServicePriorityQueue, + ConfigChangeRequest configChangeRequest) { configChangeRequest.setArg("modifyTime", TimeUtils.getCurrentTimeStr()); ConfigChangePointCutTypes handleType = configChangeRequest.getRequestType(); ConfigChangeResponse configChangeResponse = new ConfigChangeResponse(handleType); configChangeResponse.setSuccess(true); // default success,when before plugin service verify failed , set false PriorityQueue beforeExecutePriorityQueue = new PriorityQueue<>( - DEFAULT_BEFORE_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); + DEFAULT_BEFORE_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); PriorityQueue afterExecutePriorityQueue = new PriorityQueue<>( - DEFAULT_AFTER_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); - + DEFAULT_AFTER_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); + Object retVal = null; Object[] args = pjp.getArgs(); - + configChangeRequest.setArg(ConfigChangeConstants.ORIGINAL_ARGS, args); + for (ConfigChangePluginService ccs : configChangePluginServicePriorityQueue) { if (!isEnabled(ccs)) { continue; @@ -294,31 +306,16 @@ public class ConfigChangeAspect { } else { afterExecutePriorityQueue.add(ccs); } - final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT); - final Properties properties = configChangeConfigs.getPluginProperties(serviceType); - // set server config relative info to plugin - switch (serviceType) { - case "webhook": { - configChangeRequest.setArg("webhookUrl", properties.getProperty("url")); - configChangeRequest.setArg("contentMaxCapacity", properties.getProperty("contentMaxCapacity")); - break; - } - case "whitelist": { - configChangeRequest.setArg("suffixs", properties.getProperty("suffixs")); - configChangeRequest.setArg("args", args); - break; - } - default: { - // ignore - } - } } - + // before plugin service execute for (ConfigChangePluginService ccs : beforeExecutePriorityQueue) { + final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT); + final Properties properties = configChangeConfigs.getPluginProperties(serviceType); + configChangeRequest.setArg("pluginProperties", properties); ccs.execute(configChangeRequest, configChangeResponse); - if (ccs.getServiceType().equals("whitelist")) { - args = (Object[]) configChangeRequest.getArg("args"); // update args by filter with witelist + if (null != configChangeResponse.getArgs()) { + args = configChangeResponse.getArgs(); // update args by filter with whitelist } // prevent execute next before plugins service if (!configChangeResponse.isSuccess()) { @@ -326,7 +323,7 @@ public class ConfigChangeAspect { break; } } - + try { if (configChangeResponse.isSuccess()) { // if validate failed,skipped directly retVal = pjp.proceed(args); @@ -336,22 +333,26 @@ public class ConfigChangeAspect { configChangeResponse.setMsg("config change plugin proceed failed " + e.getMessage()); retVal = wrapErrorResp(configChangeResponse); } - + // after plugin service execute ConfigExecutor.executeAsyncConfigChangePluginTask(() -> { for (ConfigChangePluginService ccs : afterExecutePriorityQueue) { try { + final String serviceType = ccs.getServiceType().toLowerCase(Locale.ROOT); + final Properties properties = configChangeConfigs.getPluginProperties(serviceType); + configChangeRequest.setArg(ConfigChangeConstants.PLUGIN_PROPERTIES, properties); ccs.execute(configChangeRequest, configChangeResponse); } catch (Throwable throwable) { LOGGER.warn("execute async plugin services failed {}", throwable.getMessage()); } } }); - + return retVal; } - - private PriorityQueue getPluginServicePriorityQueue(ConfigChangePointCutTypes configChangePointCutType) { + + private PriorityQueue getPluginServicePriorityQueue( + ConfigChangePointCutTypes configChangePointCutType) { PriorityQueue pluginServicePriorityQueue = ConfigChangePluginManager .findPluginServiceQueueByPointcut(configChangePointCutType); if (pluginServicePriorityQueue == null) { @@ -364,12 +365,13 @@ public class ConfigChangeAspect { } return new PriorityQueue<>(); } - + private boolean isEnabled(ConfigChangePluginService configChangePluginService) { - Properties serviceConfigProperties = configChangeConfigs.getPluginProperties(configChangePluginService.getServiceType()); + Properties serviceConfigProperties = configChangeConfigs + .getPluginProperties(configChangePluginService.getServiceType()); return Boolean.parseBoolean(serviceConfigProperties.getProperty(ENABLED)); } - + private Object wrapErrorResp(ConfigChangeResponse configChangeResponse) { Object retVal = null; switch (configChangeResponse.getResponseType()) { @@ -382,7 +384,8 @@ public class ConfigChangeAspect { break; } case PUBLISH_BY_RPC: { - retVal = ConfigPublishResponse.buildFailResponse(ResponseCode.FAIL.getCode(), configChangeResponse.getMsg()); + retVal = ConfigPublishResponse + .buildFailResponse(ResponseCode.FAIL.getCode(), configChangeResponse.getMsg()); break; } case REMOVE_BY_RPC: { diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java index d7e64b832..f71441e68 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java @@ -40,6 +40,13 @@ public class ConfigChangeConstants { public static final String NACOS_CORE_CONFIG_PLUGIN_PREFIX = "nacos.core.config.plugin."; public static final String POINT_CUT_NAME = "CONFIG_CHANGE_POINT_CUT_TYPES_TYPES"; + + public static final String PLUGIN_PROPERTIES = "pluginProperties"; + + /** + * The actual config method args. + */ + public static final String ORIGINAL_ARGS = "originalArgs"; private static Integer pluginServiceCount = 0; diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java index 42c0f9af7..38ec1ae21 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/model/ConfigChangeResponse.java @@ -32,6 +32,8 @@ public class ConfigChangeResponse { private Object retVal; private String msg; + + private Object[] args; public ConfigChangeResponse(ConfigChangePointCutTypes responseType) { this.responseType = responseType; @@ -68,5 +70,12 @@ public class ConfigChangeResponse { public void setMsg(String msg) { this.msg = msg; } - + + public Object[] getArgs() { + return args; + } + + public void setArgs(Object[] args) { + this.args = args; + } } From f0336b86e8e9f9f4721501cfc38e65dd5496cb95 Mon Sep 17 00:00:00 2001 From: KomachiSion Date: Thu, 11 May 2023 17:19:27 +0800 Subject: [PATCH 3/5] Remove useless method and field. --- .../configuration/ConfigChangeConfigs.java | 100 +++--------------- .../constants/ConfigChangeConstants.java | 66 ++---------- 2 files changed, 20 insertions(+), 146 deletions(-) diff --git a/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java index 870be5950..7c8c273d0 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java @@ -39,79 +39,18 @@ import java.util.Properties; **/ @Configuration public class ConfigChangeConfigs extends Subscriber { - + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConfigs.class); - + private static final String PREFIX = ConfigChangeConstants.NACOS_CORE_CONFIG_PLUGIN_PREFIX; - - /** - * Whether webhook config change plugin enabled. - */ - @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED + ":false}") - private boolean webhookEnabled; - - /** - * The url which webhook. - */ - @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL + ":}") - private String webhookUrl; - - /** - * The max content capacity which webhook push. - */ - @Value("${" + ConfigChangeConstants.Webhook.NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY + ":102400}") - private int webhookContentMaxCapacity; - - /** - * Whether whitelist config change plugin enabled. - */ - @Value("${" + ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED + ":false}") - private boolean whiteListEnabled; - - /** - * Whether whitelist sets. - */ - @Value("${" + ConfigChangeConstants.WhiteList.NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS + ":}") - private String whiteListSuffixs; - - /** - * Whether file format config change plugin enabled. - */ - @Value("${" + ConfigChangeConstants.FileFormatCheck.NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED + ":false}") - private boolean fileFormatCheckEnabled; - + private Map configPluginProperties = new HashMap<>(); - + public ConfigChangeConfigs() { NotifyCenter.registerSubscriber(this); refreshPluginProperties(); } - - public boolean isWebHookEnabled() { - return webhookEnabled; - } - - public String getWebHookUrl() { - return webhookUrl; - } - - public int getWebHookMaxContentCapacity() { - // default 100kb - return webhookContentMaxCapacity; - } - - public boolean isWhiteListEnabled() { - return whiteListEnabled; - } - - public String getWhiteListSuffixs() { - return whiteListSuffixs; - } - - public boolean isFileFormatCheckEnabled() { - return whiteListEnabled; - } - + private void refreshPluginProperties() { try { Map newProperties = new HashMap<>(3); @@ -128,37 +67,22 @@ public class ConfigChangeConfigs extends Subscriber { LOGGER.warn("[ConfigChangeConfigs]Refresh config plugin properties failed ", e); } } - + public Properties getPluginProperties(String configPluginType) { if (!configPluginProperties.containsKey(configPluginType)) { - LOGGER.warn("[ConfigChangeConfigs]Can't find config plugin properties for type {}, will use empty properties", configPluginType); + LOGGER.warn( + "[ConfigChangeConfigs]Can't find config plugin properties for type {}, will use empty properties", + configPluginType); return new Properties(); } return configPluginProperties.get(configPluginType); } - + @Override public void onEvent(ServerConfigChangeEvent event) { - try { - webhookEnabled = EnvUtil.getProperty(ConfigChangeConstants.Webhook - .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED, Boolean.class); - webhookUrl = EnvUtil.getProperty(ConfigChangeConstants.Webhook - .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL, String.class); - webhookContentMaxCapacity = EnvUtil.getProperty(ConfigChangeConstants.Webhook - .NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY, Integer.class); - whiteListEnabled = EnvUtil.getProperty(ConfigChangeConstants.WhiteList - .NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED, Boolean.class); - whiteListSuffixs = EnvUtil.getProperty(ConfigChangeConstants.WhiteList - .NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS, String.class); - fileFormatCheckEnabled = EnvUtil.getProperty(ConfigChangeConstants.FileFormatCheck - .NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED, Boolean.class); - LOGGER.info("[ConfigChangeConfigs]Upgrade config change plugin configs successfully, {} enabled:{} , {} enabled:{}, {} enbaled: {}", - "webhook", isWebHookEnabled(), "fileformatcheck", isFileFormatCheckEnabled(), "whitelist", isWhiteListEnabled()); - } catch (Exception e) { - LOGGER.warn("[ConfigChangeConfigs]Upgrade config change plugin config from env failed, use old value", e); - } + refreshPluginProperties(); } - + @Override public Class subscribeType() { return ServerConfigChangeEvent.class; diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java index f71441e68..f2deb4c9d 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java @@ -29,16 +29,16 @@ import java.util.concurrent.ConcurrentHashMap; * @author liyunfei */ public class ConfigChangeConstants { - + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConstants.class); - + /** * The relationship of config change plugin service name and its pointcuts. */ private static final Map POINTCUTS_MAP = new ConcurrentHashMap(); - + public static final String NACOS_CORE_CONFIG_PLUGIN_PREFIX = "nacos.core.config.plugin."; - + public static final String POINT_CUT_NAME = "CONFIG_CHANGE_POINT_CUT_TYPES_TYPES"; public static final String PLUGIN_PROPERTIES = "pluginProperties"; @@ -47,59 +47,9 @@ public class ConfigChangeConstants { * The actual config method args. */ public static final String ORIGINAL_ARGS = "originalArgs"; - + private static Integer pluginServiceCount = 0; - - /** - * Webhook plugin service relevant server configs. - */ - public static class Webhook { - - /** - * The plugin service will execute when the action produce. - */ - public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = ConfigChangePointCutTypes - .values(); - - public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_ENABLED = "nacos.core.config.plugin.webhook.enabled"; - - public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_URL = "nacos.core.config.plugin.webhook.url"; - - public static final String NACOS_CORE_CONFIG_PLUGIN_WEBHOOK_CONTENT_MAX_CAPACITY = "nacos.core.config.plugin.webhook.contentMaxCapacity"; - } - - /** - * File format check plugin service relevant server configs. - */ - public static class FileFormatCheck { - - /** - * The plugin service will execute when the action produce. - */ - public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = { - ConfigChangePointCutTypes.PUBLISH_BY_HTTP, ConfigChangePointCutTypes.PUBLISH_BY_RPC}; - - public static final String NACOS_CORE_CONFIG_PLUGIN_FILEFORMATCHECK_ENABLED = "nacos.core.config.plugin.fileformatcheck.enabled"; - - } - - /** - * WhiteList plugin service relevant server configs. - */ - public static class WhiteList { - - /** - * The plugin service will execute when the action produce. - */ - public static final ConfigChangePointCutTypes[] CONFIG_CHANGE_POINT_CUT_TYPES_TYPES = { - ConfigChangePointCutTypes.IMPORT_BY_HTTP}; - - public static final String NACOS_CORE_CONFIG_PLUGIN_WHITELIST_ENABLED = "nacos.core.config.plugin.whitelist.enabled"; - - public static final String NACOS_CORE_CONFIG_PLUGIN_WHITELIST_SUFFIXS = "nacos.core.config.plugin.whitelist.suffixs"; - - } - + // Load config pointcuts to each config change plugin services. static { Class[] innerClasses = ConfigChangeConstants.class.getDeclaredClasses(); @@ -115,11 +65,11 @@ public class ConfigChangeConstants { } } } - + public static ConfigChangePointCutTypes[] getPointcuts(String serviceType) { return POINTCUTS_MAP.get(serviceType); } - + public static Integer getPluginServiceCount() { return pluginServiceCount; } From 5897a61e8e6753fb1bb7842904b5640f1bf81f77 Mon Sep 17 00:00:00 2001 From: KomachiSion Date: Thu, 11 May 2023 20:09:33 +0800 Subject: [PATCH 4/5] Fix start error. --- .../configuration/ConfigChangeConfigs.java | 1 - .../EmbeddedConfigInfoPersistServiceImpl.java | 2 +- .../config/ConfigChangePluginManager.java | 57 ++++++++++--------- .../constants/ConfigChangeConstants.java | 41 ------------- .../config/spi/ConfigChangePluginService.java | 4 +- 5 files changed, 32 insertions(+), 73 deletions(-) diff --git a/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java index 7c8c273d0..0d348cba5 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/configuration/ConfigChangeConfigs.java @@ -25,7 +25,6 @@ import com.alibaba.nacos.sys.env.EnvUtil; import com.alibaba.nacos.sys.utils.PropertiesUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import java.util.HashMap; diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedConfigInfoPersistServiceImpl.java b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedConfigInfoPersistServiceImpl.java index 6ad326f79..ca139ac50 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedConfigInfoPersistServiceImpl.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedConfigInfoPersistServiceImpl.java @@ -475,7 +475,7 @@ public class EmbeddedConfigInfoPersistServiceImpl implements ConfigInfoPersistSe MapperContext context = new MapperContext(); context.putWhereParameter(FieldConstant.IDS, paramList); MapperResult result = configInfoMapper.removeConfigInfoByIdsAtomic(context); - EmbeddedStorageContextHolder.addSqlContext(result.getSql(), result.getParamList()); + EmbeddedStorageContextHolder.addSqlContext(result.getSql(), result.getParamList().toArray()); } @Override diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java index 294ce6787..a47d13e33 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/ConfigChangePluginManager.java @@ -18,17 +18,16 @@ package com.alibaba.nacos.plugin.config; import com.alibaba.nacos.common.spi.NacosServiceLoader; import com.alibaba.nacos.common.utils.StringUtils; -import com.alibaba.nacos.plugin.config.constants.ConfigChangeConstants; import com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes; import com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map; import java.util.Collection; -import java.util.PriorityQueue; -import java.util.Optional; import java.util.Comparator; +import java.util.Map; +import java.util.Optional; +import java.util.PriorityQueue; import java.util.concurrent.ConcurrentHashMap; /** @@ -37,38 +36,39 @@ import java.util.concurrent.ConcurrentHashMap; * @author liyunfei */ public class ConfigChangePluginManager { - + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangePluginManager.class); - - private static final Integer PLUGIN_SERVICE_COUNT = ConfigChangeConstants.getPluginServiceCount(); - + + private static final Integer PLUGIN_SERVICE_COUNT = 2; + private static final Integer POINT_CUT_TYPE_COUNT = ConfigChangePointCutTypes.values().length; - + /** * The relationship of serviceType and {@link ConfigChangePluginService} ,default capacity is the count of plugin * service. */ - private static Map configChangeServiceMap = new ConcurrentHashMap<>( + private static final Map CONFIG_CHANGE_PLUGIN_SERVICE_MAP = new ConcurrentHashMap<>( PLUGIN_SERVICE_COUNT); - + /** - * The relationship of config change pointcut type and the queue of {@link ConfigChangePluginService} will pointcut it, - * default capacity is the count of pointcutTypes. + * The relationship of config change pointcut type and the queue of {@link ConfigChangePluginService} will pointcut + * it, default capacity is the count of pointcutTypes. */ private static Map> priorityQueueMap = new ConcurrentHashMap<>( POINT_CUT_TYPE_COUNT); - + private static final ConfigChangePluginManager INSTANCE = new ConfigChangePluginManager(); - + private ConfigChangePluginManager() { loadConfigChangeServices(); } - + /** * Load all config change plugin services by spi. */ private static void loadConfigChangeServices() { - Collection configChangePluginServices = NacosServiceLoader.load(ConfigChangePluginService.class); + Collection configChangePluginServices = NacosServiceLoader + .load(ConfigChangePluginService.class); // load all config change plugin by spi for (ConfigChangePluginService each : configChangePluginServices) { if (StringUtils.isEmpty(each.getServiceType())) { @@ -77,18 +77,18 @@ public class ConfigChangePluginManager { each.getClass().getName(), each.getClass()); continue; } - configChangeServiceMap.put(each.getServiceType(), each); + CONFIG_CHANGE_PLUGIN_SERVICE_MAP.put(each.getServiceType(), each); LOGGER.info("[ConfigChangePluginManager] Load {}({}) ConfigChangeServiceName({}) successfully.", each.getClass().getName(), each.getClass(), each.getServiceType()); // map the relationship of pointcut and plugin service addPluginServiceByPointCut(each); } } - + public static ConfigChangePluginManager getInstance() { return INSTANCE; } - + /** * Dynamic get any pluginServiceImpl. * @@ -96,9 +96,9 @@ public class ConfigChangePluginManager { * @return */ public Optional findPluginServiceImpl(String serviceType) { - return Optional.ofNullable(configChangeServiceMap.get(serviceType)); + return Optional.ofNullable(CONFIG_CHANGE_PLUGIN_SERVICE_MAP.get(serviceType)); } - + /** * Dynamic add new ConfigChangeService. * @@ -106,25 +106,28 @@ public class ConfigChangePluginManager { * @return */ public static synchronized boolean join(ConfigChangePluginService configChangePluginService) { - configChangeServiceMap.putIfAbsent(configChangePluginService.getServiceType(), configChangePluginService); + CONFIG_CHANGE_PLUGIN_SERVICE_MAP + .putIfAbsent(configChangePluginService.getServiceType(), configChangePluginService); addPluginServiceByPointCut(configChangePluginService); return true; } - + /** * Get the plugin service queue of the pointcut method. * * @param pointcutName pointcut method name,detail see {@link ConfigChangePointCutTypes}. * @return */ - public static PriorityQueue findPluginServiceQueueByPointcut(ConfigChangePointCutTypes pointcutName) { + public static PriorityQueue findPluginServiceQueueByPointcut( + ConfigChangePointCutTypes pointcutName) { return priorityQueueMap.getOrDefault(pointcutName, new PriorityQueue<>()); } - + private static boolean addPluginServiceByPointCut(ConfigChangePluginService configChangePluginService) { ConfigChangePointCutTypes[] pointcutNames = configChangePluginService.pointcutMethodNames(); for (ConfigChangePointCutTypes name : pointcutNames) { - PriorityQueue configChangePluginServicePriorityQueue = priorityQueueMap.get(name); + PriorityQueue configChangePluginServicePriorityQueue = priorityQueueMap + .get(name); if (configChangePluginServicePriorityQueue == null) { configChangePluginServicePriorityQueue = new PriorityQueue<>(PLUGIN_SERVICE_COUNT, Comparator.comparingInt(ConfigChangePluginService::getOrder)); diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java index f2deb4c9d..533c89081 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/constants/ConfigChangeConstants.java @@ -16,13 +16,6 @@ package com.alibaba.nacos.plugin.config.constants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * Config change plugin service constants. * @@ -30,17 +23,8 @@ import java.util.concurrent.ConcurrentHashMap; */ public class ConfigChangeConstants { - private static final Logger LOGGER = LoggerFactory.getLogger(ConfigChangeConstants.class); - - /** - * The relationship of config change plugin service name and its pointcuts. - */ - private static final Map POINTCUTS_MAP = new ConcurrentHashMap(); - public static final String NACOS_CORE_CONFIG_PLUGIN_PREFIX = "nacos.core.config.plugin."; - public static final String POINT_CUT_NAME = "CONFIG_CHANGE_POINT_CUT_TYPES_TYPES"; - public static final String PLUGIN_PROPERTIES = "pluginProperties"; /** @@ -48,30 +32,5 @@ public class ConfigChangeConstants { */ public static final String ORIGINAL_ARGS = "originalArgs"; - private static Integer pluginServiceCount = 0; - - // Load config pointcuts to each config change plugin services. - static { - Class[] innerClasses = ConfigChangeConstants.class.getDeclaredClasses(); - for (Class clazz : innerClasses) { - try { - POINTCUTS_MAP.put(clazz.getSimpleName().toLowerCase(Locale.ROOT), - (ConfigChangePointCutTypes[]) clazz.getField(POINT_CUT_NAME).get(null)); - pluginServiceCount++; - } catch (NoSuchFieldException | IllegalAccessException e) { - LOGGER.warn( - "[{}] Load config change plugin service to relevant pointcuts failed,please check {} at {} ", - ConfigChangeConstants.class, POINT_CUT_NAME, clazz); - } - } - } - - public static ConfigChangePointCutTypes[] getPointcuts(String serviceType) { - return POINTCUTS_MAP.get(serviceType); - } - - public static Integer getPluginServiceCount() { - return pluginServiceCount; - } } diff --git a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java index bb9afdb94..888ddcbc6 100644 --- a/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java +++ b/plugin/config/src/main/java/com/alibaba/nacos/plugin/config/spi/ConfigChangePluginService.java @@ -69,8 +69,6 @@ public interface ConfigChangePluginService { * * @return array of pointcut the methods */ - default ConfigChangePointCutTypes[] pointcutMethodNames() { - return ConfigChangeConstants.getPointcuts(getServiceType()); - } + ConfigChangePointCutTypes[] pointcutMethodNames(); } From dc79f058383b3681c3ece4dabc2febb40ae85a26 Mon Sep 17 00:00:00 2001 From: KomachiSion Date: Fri, 12 May 2023 10:14:21 +0800 Subject: [PATCH 5/5] For pmd --- .../nacos/config/server/aspect/ConfigChangeAspect.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java index 2c8c95935..efb2b2d58 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/aspect/ConfigChangeAspect.java @@ -287,7 +287,8 @@ public class ConfigChangeAspect { configChangeRequest.setArg("modifyTime", TimeUtils.getCurrentTimeStr()); ConfigChangePointCutTypes handleType = configChangeRequest.getRequestType(); ConfigChangeResponse configChangeResponse = new ConfigChangeResponse(handleType); - configChangeResponse.setSuccess(true); // default success,when before plugin service verify failed , set false + // default success,when before plugin service verify failed , set false + configChangeResponse.setSuccess(true); PriorityQueue beforeExecutePriorityQueue = new PriorityQueue<>( DEFAULT_BEFORE_QUEUE_CAPACITY, Comparator.comparingInt(ConfigChangePluginService::getOrder)); PriorityQueue afterExecutePriorityQueue = new PriorityQueue<>( @@ -315,7 +316,8 @@ public class ConfigChangeAspect { configChangeRequest.setArg("pluginProperties", properties); ccs.execute(configChangeRequest, configChangeResponse); if (null != configChangeResponse.getArgs()) { - args = configChangeResponse.getArgs(); // update args by filter with whitelist + // update args by filter with whitelist + args = configChangeResponse.getArgs(); } // prevent execute next before plugins service if (!configChangeResponse.isSuccess()) { @@ -325,7 +327,8 @@ public class ConfigChangeAspect { } try { - if (configChangeResponse.isSuccess()) { // if validate failed,skipped directly + // if validate failed,skipped directly + if (configChangeResponse.isSuccess()) { retVal = pjp.proceed(args); } } catch (Throwable e) {