Skip to content

Commit

Permalink
Merge pull request #1534 from lilai23/1.4.x
Browse files Browse the repository at this point in the history
[1.4.x] fix issue of plugin config reload dynamically failure
  • Loading branch information
lilai23 authored Jun 5, 2024
2 parents ba82cb6 + 3a92774 commit 5fab473
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private static synchronized void doLoadConfig(File configFile,
final String typeKey = ConfigKeyUtil.getTypeKey(config.getClass());
final BaseConfig retainedConfig = CONFIG_MAP.get(typeKey);
if (retainedConfig == null) {
CONFIG_MAP.put(typeKey, doLoad(configFile, config));
CONFIG_MAP.put(typeKey, doLoad(configFile, config, false));
} else if (retainedConfig.getClass() == config.getClass()) {
LOGGER.fine(String.format(Locale.ROOT, "Skip load config [%s] repeatedly. ",
config.getClass().getName()));
Expand All @@ -159,14 +159,15 @@ private static synchronized void doLoadConfig(File configFile,
*
* @param configFile 配置文件
* @param baseConfig 配置类
* @param isDynamic is the config loaded dynamically
* @return 加载后的配置类
*/
public static BaseConfig doLoad(File configFile, BaseConfig baseConfig) {
public static BaseConfig doLoad(File configFile, BaseConfig baseConfig, boolean isDynamic) {
// 通过FrameworkClassLoader 获取配置加载策略
final LoadConfigStrategy<?> loadConfigStrategy = getLoadConfigStrategy(configFile,
ClassLoaderManager.getFrameworkClassLoader());
final Object holder = loadConfigStrategy.getConfigHolder(configFile, argsMap);
return ((LoadConfigStrategy) loadConfigStrategy).loadConfig(holder, baseConfig);
return ((LoadConfigStrategy) loadConfigStrategy).loadConfig(holder, baseConfig, isDynamic);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* <p>加载配置信息主要分两步:
* <pre>
* 1.加载配置文件为配置信息{@link #getConfigHolder(File, Map)}
* 2.将配置信息加载到配置对象中{@link #loadConfig(Object, BaseConfig)}
* 2.将配置信息加载到配置对象中{@link #loadConfig(Object, BaseConfig, boolean)}
* </pre>
*
* @param <T> 配置主体
Expand Down Expand Up @@ -70,9 +70,10 @@ public interface LoadConfigStrategy<T> {
* @param holder 配置信息主要承载对象
* @param config 配置对象
* @param <R> 配置对象类型
* @param isDynamic is the config loaded dynamically
* @return 配置对象
*/
<R extends BaseConfig> R loadConfig(T holder, R config);
<R extends BaseConfig> R loadConfig(T holder, R config, boolean isDynamic);

/**
* 默认的{@link LoadConfigStrategy},不做任何逻辑操作
Expand All @@ -96,7 +97,7 @@ public Object getConfigHolder(File config, Map<String, Object> argsMap) {
}

@Override
public <R extends BaseConfig> R loadConfig(Object holder, R config) {
public <R extends BaseConfig> R loadConfig(Object holder, R config, boolean isDynamic) {
LOGGER.log(Level.WARNING, String.format(Locale.ROOT, "[%s] will do nothing when loading config. ",
DefaultLoadConfigStrategy.class.getName()));
return config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public static void loadPluginConfigs(Plugin plugin) {
final BaseConfig retainedConfig = PLUGIN_CONFIG_MAP.get(pluginConfigKey);
if (pluginConfigFile.exists() && pluginConfigFile.isFile()) {
if (retainedConfig == null) {
PLUGIN_CONFIG_MAP.put(pluginConfigKey, ConfigManager.doLoad(pluginConfigFile, config));
PLUGIN_CONFIG_MAP.put(pluginConfigKey,
ConfigManager.doLoad(pluginConfigFile, config, plugin.isDynamic()));
plugin.getConfigs().add(pluginConfigKey);
} else if (retainedConfig.getClass() == pluginConfigCls) {
LOGGER.fine(String.format(Locale.ROOT, "Skip load config [%s] repeatedly. ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public Properties getConfigHolder(File config, Map<String, Object> bootArgsMap)
* @return 配置对象泛型
*/
@Override
public <R extends BaseConfig> R loadConfig(Properties holder, R config) {
public <R extends BaseConfig> R loadConfig(Properties holder, R config, boolean isDynamic) {
return loadConfig(holder, config.getClass(), config);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,16 @@ public class LoadYamlStrategy implements LoadConfigStrategy<Map> {
*/
private Map<String, Object> argsMap;

private final SermantYamlConstructor constructor;

/**
* 构造函数
*/
public LoadYamlStrategy() {
Representer representer = new Representer(new DumperOptions());
representer.getPropertyUtils().setSkipMissingProperties(true);
this.yaml = new Yaml(representer);
this.constructor = new SermantYamlConstructor();
this.yaml = new Yaml(constructor, representer);
}

@Override
Expand All @@ -107,7 +110,7 @@ public Map getConfigHolder(File config, Map<String, Object> bootstreapArgsMap) {
}

@Override
public <R extends BaseConfig> R loadConfig(Map holder, R config) {
public <R extends BaseConfig> R loadConfig(Map holder, R config, boolean isDynamic) {
final Class<R> cls = (Class<R>) config.getClass();
final String typeKey = ConfigKeyUtil.getTypeKey(cls);
final Object typeVal = holder.get(typeKey);
Expand All @@ -124,13 +127,11 @@ public <R extends BaseConfig> R loadConfig(Map holder, R config) {
configMap.put(field.getName(), null);
}
}
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(cls.getClassLoader());
return (R) yaml.loadAs(yaml.dump(fixEntry(configMap, cls)), cls);
} finally {
Thread.currentThread().setContextClassLoader(classLoader);
constructor.setLoader(cls.getClassLoader());
if (isDynamic) {
constructor.clearCache();
}
return (R) yaml.loadAs(yaml.dump(fixEntry(configMap, cls)), cls);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2024-2024 Sermant Authors. 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.implement.config;

import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.constructor.Constructor;

/**
* Yaml constructor for sermant config load
*
* @author lilai
* @since 2024-05-22
*/
public class SermantYamlConstructor extends Constructor {
private ClassLoader loader;

/**
* constructor
*/
public SermantYamlConstructor() {
super(Object.class, new LoaderOptions());
loader = Thread.currentThread().getContextClassLoader();
}

/**
* Load class with specific classLoader
*
* @param name class name
* @return created class
* @throws ClassNotFoundException class not found
*/
@Override
protected Class<?> getClassForName(String name) throws ClassNotFoundException {
return Class.forName(name, true, loader);
}

/**
* set classLoader
*
* @param classLoader the classLoader for config object
* @throws NullPointerException no classloader is provided
*/
public void setLoader(ClassLoader classLoader) {
if (classLoader == null) {
throw new NullPointerException("classLoader must be provided.");
}
this.loader = classLoader;
}

/**
* clear snakeyaml class cache
*/
public void clearCache() {
typeTags.clear();
}
}

0 comments on commit 5fab473

Please sign in to comment.