diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java index 88b38a1f37..209db2bc30 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/PluginManager.java @@ -168,7 +168,8 @@ public static void initPlugins(Set pluginNames, boolean isDynamic) { continue; } try { - final String pluginPath = pluginPackage + File.separatorChar + pluginName; + // 去除插件名副本标记,获取实际所需要用到的资源目录 + final String pluginPath = pluginPackage + File.separatorChar + getRealPluginName(pluginName); if (!new File(pluginPath).exists()) { LOGGER.log(Level.WARNING, "Plugin directory {0} does not exist, so skip initializing {1}. ", new String[]{pluginPath, pluginName}); @@ -284,7 +285,8 @@ private static boolean processByJarFile(String pluginName, File jar, boolean ifC JarFile jarFile = null; try { jarFile = new JarFile(jar); - if (ifCheckSchema && !PluginSchemaValidator.checkSchema(pluginName, jarFile)) { + if (ifCheckSchema && !PluginSchemaValidator.checkSchema(pluginName, getRealPluginName(pluginName), + jarFile)) { throw new SchemaException(SchemaException.UNEXPECTED_EXT_JAR, jar.getPath()); } if (consumer != null) { @@ -305,6 +307,16 @@ private static boolean processByJarFile(String pluginName, File jar, boolean ifC } } + /** + * 形如 plugin-name#1 plugin-name#2 方式标记插件副本,共用资源文件,通过分隔插件名获取实际的插件名,对应插件目录名及Manifest中的插件标识 + * + * @param pluginName 插件名 + * @return 实际插件名 + */ + private static String getRealPluginName(String pluginName) { + return pluginName.split("#")[0]; + } + /** * 遍历目录下所有jar包,按文件名字典序排列 * diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/common/PluginSchemaValidator.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/common/PluginSchemaValidator.java index e2e7eedf9d..355a64920a 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/common/PluginSchemaValidator.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/common/PluginSchemaValidator.java @@ -73,28 +73,29 @@ public static void removePluginVersionCache(String pluginName) { /** * 检查名称和版本 * - * @param name 插件名称 + * @param pluginName 插件名称 + * @param realPluginName 实际插件名,插件名去除副本标记后的所使用的插件 * @param jarFile 插件包 * @return 为真时经过名称和版本校验,为插件包或插件服务包,为假时表示第三方jar包 * @throws IOException 获取manifest文件异常 * @throws SchemaException 传入插件名和从资源文件中检索到的不一致 */ - public static boolean checkSchema(String name, JarFile jarFile) throws IOException { + public static boolean checkSchema(String pluginName, String realPluginName, JarFile jarFile) throws IOException { final Object nameAttr = JarFileUtils.getManifestAttr(jarFile, PluginConstant.PLUGIN_NAME_KEY); if (nameAttr == null) { return false; } - if (!nameAttr.toString().equals(name)) { - throw new SchemaException(SchemaException.UNEXPECTED_NAME, nameAttr.toString(), name); + if (!nameAttr.toString().equals(realPluginName)) { + throw new SchemaException(SchemaException.UNEXPECTED_NAME, nameAttr.toString(), pluginName); } final Object versionAttr = JarFileUtils.getManifestAttr(jarFile, PluginConstant.PLUGIN_VERSION_KEY); final String givingVersion = versionAttr == null ? PluginConstant.PLUGIN_DEFAULT_VERSION : versionAttr.toString(); - final String expectingVersion = PLUGIN_VERSION_MAP.get(name); + final String expectingVersion = PLUGIN_VERSION_MAP.get(pluginName); if (expectingVersion == null) { - PLUGIN_VERSION_MAP.put(name, givingVersion); + PLUGIN_VERSION_MAP.put(pluginName, givingVersion); } else if (!expectingVersion.equals(givingVersion)) { - throw new SchemaException(SchemaException.UNEXPECTED_VERSION, name, givingVersion, expectingVersion); + throw new SchemaException(SchemaException.UNEXPECTED_VERSION, pluginName, givingVersion, expectingVersion); } return true; } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/config/PluginConfigManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/config/PluginConfigManager.java index a9e3613ad8..81655a847a 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/config/PluginConfigManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/config/PluginConfigManager.java @@ -63,28 +63,30 @@ public static void loadPluginConfigs(Plugin plugin) { ClassLoader classLoader = plugin.getServiceClassLoader() != null ? plugin.getServiceClassLoader() : plugin.getPluginClassLoader(); for (BaseConfig config : ServiceLoader.load(PluginConfig.class, classLoader)) { - final String typeKey = ConfigKeyUtil.getTypeKey(config.getClass()); - final BaseConfig retainedConfig = PLUGIN_CONFIG_MAP.get(typeKey); + Class pluginConfigCls = config.getClass(); + String pluginConfigKey = ConfigKeyUtil.getCLTypeKey(ConfigKeyUtil.getTypeKey(pluginConfigCls), + pluginConfigCls.getClassLoader()); + final BaseConfig retainedConfig = PLUGIN_CONFIG_MAP.get(pluginConfigKey); if (pluginConfigFile.exists() && pluginConfigFile.isFile()) { if (retainedConfig == null) { - PLUGIN_CONFIG_MAP.put(typeKey, ConfigManager.doLoad(pluginConfigFile, config)); - plugin.getConfigs().add(typeKey); - } else if (retainedConfig.getClass() == config.getClass()) { + PLUGIN_CONFIG_MAP.put(pluginConfigKey, ConfigManager.doLoad(pluginConfigFile, config)); + plugin.getConfigs().add(pluginConfigKey); + } else if (retainedConfig.getClass() == pluginConfigCls) { LOGGER.fine(String.format(Locale.ROOT, "Skip load config [%s] repeatedly. ", - config.getClass().getName())); + pluginConfigCls.getName())); } else { LOGGER.warning(String.format(Locale.ROOT, "Type key of %s is %s, same as %s's. ", - config.getClass().getName(), typeKey, retainedConfig.getClass().getName())); + pluginConfigCls.getName(), pluginConfigKey, retainedConfig.getClass().getName())); } continue; } - if (PLUGIN_CONFIG_MAP.containsKey(typeKey)) { + if (PLUGIN_CONFIG_MAP.containsKey(pluginConfigKey)) { continue; } // 不能从文件加载,则为默认配置 - PLUGIN_CONFIG_MAP.put(typeKey, config); - plugin.getConfigs().add(typeKey); + PLUGIN_CONFIG_MAP.put(pluginConfigKey, config); + plugin.getConfigs().add(pluginConfigKey); } } @@ -107,7 +109,8 @@ public static void cleanPluginConfigs(Plugin plugin) { * @return 插件配置实例 */ public static R getPluginConfig(Class cls) { - return (R) PLUGIN_CONFIG_MAP.get(ConfigKeyUtil.getTypeKey(cls)); + String pluginConfigKey = ConfigKeyUtil.getCLTypeKey(ConfigKeyUtil.getTypeKey(cls), cls.getClassLoader()); + return (R) PLUGIN_CONFIG_MAP.get(pluginConfigKey); } /** diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/service/PluginServiceManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/service/PluginServiceManager.java index 425aa572e8..3af2ca8b55 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/service/PluginServiceManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/plugin/service/PluginServiceManager.java @@ -20,6 +20,7 @@ import com.huaweicloud.sermant.core.event.collector.FrameworkEventCollector; import com.huaweicloud.sermant.core.plugin.Plugin; import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.core.utils.KeyGenerateUtils; import java.util.ServiceLoader; import java.util.logging.Level; @@ -50,9 +51,9 @@ public static void initPluginServices(Plugin plugin) { for (PluginService service : ServiceLoader.load(PluginService.class, classLoader)) { if (loadService(service, service.getClass(), PluginService.class)) { try { - String serviceName = service.getClass().getName(); + String pluginServiceKey = KeyGenerateUtils.generateClassKeyWithClassLoader(service.getClass()); service.start(); - plugin.getServices().add(serviceName); + plugin.getServices().add(pluginServiceKey); } catch (Exception ex) { LOGGER.log(Level.SEVERE, "Error occurs while starting plugin service: " + service.getClass(), ex); } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/service/ServiceManager.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/service/ServiceManager.java index fa06e68bb7..b589d28200 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/service/ServiceManager.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/service/ServiceManager.java @@ -28,7 +28,7 @@ import com.huaweicloud.sermant.core.event.EventManager; import com.huaweicloud.sermant.core.event.collector.FrameworkEventCollector; import com.huaweicloud.sermant.core.exception.DupServiceException; -import com.huaweicloud.sermant.core.service.send.api.GatewayClient; +import com.huaweicloud.sermant.core.utils.KeyGenerateUtils; import com.huaweicloud.sermant.core.utils.SpiLoadUtils; import java.util.ArrayList; @@ -121,7 +121,8 @@ public static void initServices() { * @throws IllegalArgumentException IllegalArgumentException 找不到对应的服务 */ public static T getService(Class serviceClass) { - final BaseService baseService = SERVICES.get(serviceClass.getName()); + String serviceKey = KeyGenerateUtils.generateClassKeyWithClassLoader(serviceClass); + final BaseService baseService = SERVICES.get(serviceKey); if (baseService != null && serviceClass.isAssignableFrom(baseService.getClass())) { return (T) baseService; } @@ -141,8 +142,8 @@ protected static boolean loadService(BaseService service, Class serviceCls, if (serviceCls == null || serviceCls == baseCls || !baseCls.isAssignableFrom(serviceCls)) { return false; } - final String serviceName = serviceCls.getName(); - final BaseService oldService = SERVICES.get(serviceName); + final String serviceKey = KeyGenerateUtils.generateClassKeyWithClassLoader(serviceCls); + final BaseService oldService = SERVICES.get(serviceKey); if (oldService != null && oldService.getClass() == service.getClass()) { return false; } @@ -151,11 +152,11 @@ protected static boolean loadService(BaseService service, Class serviceCls, SpiLoadUtils.getBetter(oldService, service, new SpiLoadUtils.WeightEqualHandler() { @Override public BaseService handle(BaseService source, BaseService target) { - throw new DupServiceException(serviceName); + throw new DupServiceException(serviceKey); } }); if (betterService != oldService) { - SERVICES.put(serviceName, service); + SERVICES.put(serviceKey, service); isLoadSucceed = true; } isLoadSucceed |= loadService(service, serviceCls.getSuperclass(), baseCls); diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/KeyGenerateUtils.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/KeyGenerateUtils.java new file mode 100644 index 0000000000..e03e700f82 --- /dev/null +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/com/huaweicloud/sermant/core/utils/KeyGenerateUtils.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved. + * + * 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.huaweicloud.sermant.core.utils; + +/** + * 生成各类键 + * + * @author luanwenfei + * @since 2023-10-19 + */ +public class KeyGenerateUtils { + private KeyGenerateUtils() { + } + + /** + * 通过Class生成携带类加载器信息的键 + * + * @param cls 类 + * @return 键 + */ + public static String generateClassKeyWithClassLoader(Class cls) { + return cls.getName() + "@" + System.identityHashCode(cls.getClassLoader()); + } +} diff --git a/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/NacosRegistryFactoryTest.java b/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/NacosRegistryFactoryTest.java index 7db8e23d05..b5d1d0e94d 100644 --- a/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/NacosRegistryFactoryTest.java +++ b/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/NacosRegistryFactoryTest.java @@ -30,6 +30,7 @@ import com.huawei.dubbo.registry.service.nacos.NacosRegistryService; import com.huaweicloud.sermant.core.service.BaseService; import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.core.utils.KeyGenerateUtils; /** * 测试NacosRegistryFactory @@ -45,7 +46,8 @@ public NacosRegistryFactoryTest() throws NoSuchFieldException, IllegalAccessExce Field field = ServiceManager.class.getDeclaredField("SERVICES"); field.setAccessible(true); Map map = (Map) field.get(null); - map.put(NacosRegistryService.class.getCanonicalName(), new NacosRegistryService() { + map.put(KeyGenerateUtils.generateClassKeyWithClassLoader(NacosRegistryService.class), + new NacosRegistryService() { @Override public void doRegister(Object url) { diff --git a/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/RegistryFactoryTest.java b/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/RegistryFactoryTest.java index 0b11c80479..988a9f7304 100644 --- a/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/RegistryFactoryTest.java +++ b/sermant-plugins/sermant-service-registry/dubbo-registry-plugin/src/test/java/com/huawei/dubbo/registry/RegistryFactoryTest.java @@ -22,6 +22,7 @@ import com.huaweicloud.sermant.core.service.BaseService; import com.huaweicloud.sermant.core.service.ServiceManager; +import com.huaweicloud.sermant.core.utils.KeyGenerateUtils; import com.alibaba.dubbo.common.URL; @@ -47,7 +48,7 @@ public RegistryFactoryTest() throws NoSuchFieldException, IllegalAccessException Field field = ServiceManager.class.getDeclaredField("SERVICES"); field.setAccessible(true); Map map = (Map) field.get(null); - map.put(RegistryService.class.getCanonicalName(), new RegistryService() { + map.put(KeyGenerateUtils.generateClassKeyWithClassLoader(RegistryService.class), new RegistryService() { @Override public void startRegistration() { } diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-service/src/test/java/com/huawei/registry/service/client/BaseTest.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-service/src/test/java/com/huawei/registry/service/client/BaseTest.java index 59018edb20..ce793c6a8e 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-service/src/test/java/com/huawei/registry/service/client/BaseTest.java +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-service/src/test/java/com/huawei/registry/service/client/BaseTest.java @@ -17,10 +17,11 @@ package com.huawei.registry.service.client; import com.huawei.registry.config.RegisterConfig; - import com.huawei.registry.config.RegisterServiceCommonConfig; + import com.huaweicloud.sermant.core.config.ConfigManager; import com.huaweicloud.sermant.core.config.common.BaseConfig; +import com.huaweicloud.sermant.core.config.utils.ConfigKeyUtil; import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager; import org.junit.BeforeClass; @@ -49,15 +50,18 @@ public static void init() throws IllegalAccessException, NoSuchFieldException, C removeFinalModify(configMap); configManagerMap = (Map) configMap.get(null); - configManagerMap.put("servicecomb.service", new RegisterConfig()); - configManagerMap.put("register.service", new RegisterServiceCommonConfig()); + configManagerMap.put(ConfigKeyUtil.getCLTypeKey("servicecomb.service", RegisterConfig.class.getClassLoader()), + new RegisterConfig()); + configManagerMap.put( + ConfigKeyUtil.getCLTypeKey("register.service", RegisterServiceCommonConfig.class.getClassLoader()), + new RegisterServiceCommonConfig()); } /** * 移除final修饰符 * * @param field 字段 - * @throws NoSuchFieldException 无该字段抛出 + * @throws NoSuchFieldException 无该字段抛出 * @throws IllegalAccessException 无法拿到该字段抛出 */ protected static void removeFinalModify(Field field) throws NoSuchFieldException, IllegalAccessException {