Skip to content

Commit

Permalink
*fix spi classloader
Browse files Browse the repository at this point in the history
Signed-off-by: chengyouling <spadgerlin888@163.com>
  • Loading branch information
provenceee authored and chengyouling committed Jan 7, 2025
1 parent 5185ebd commit 41b4113
Show file tree
Hide file tree
Showing 32 changed files with 101 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class ClassLoaderManager {

private static FrameworkClassLoader frameworkClassLoader;

private static ClassLoader userClassLoader;

private ClassLoaderManager() {
}

Expand Down Expand Up @@ -88,6 +90,23 @@ public PluginClassLoader run() {
});
}

public static void setUserClassLoader(ClassLoader userClassLoader) {
ClassLoaderManager.userClassLoader = userClassLoader;
}

/**
* get ContextClassLoader or UserClassLoader
*
* @return ClassLoader
*/
public static ClassLoader getContextClassLoaderOrUserClassLoader() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
return classLoader;
}
return userClassLoader;
}

public static SermantClassLoader getSermantClassLoader() {
return sermantClassLoader;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public ClassLoaderLoadClassInterceptor() {

@Override
public ExecuteContext before(ExecuteContext context) throws Exception {
ClassLoaderManager.setUserClassLoader((ClassLoader) context.getObject());
return context;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.sermant.core.plugin.classloader;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.config.ConfigManager;
import io.sermant.core.plugin.agent.config.AgentConfig;
Expand Down Expand Up @@ -133,9 +134,16 @@ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundExce

private Class<?> getClassFromLocalClassLoader(String name) {
ClassLoader loader = localLoader.get(Thread.currentThread().getId());

if (loader == null) {
LOGGER.log(Level.FINE, "localLoader is null, thread name is {0}, classs name is {1}.",
new Object[]{Thread.currentThread().getName(), name});
}
if (loader == null && useContextLoader) {
loader = Thread.currentThread().getContextClassLoader();
loader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
if (loader == null) {
LOGGER.log(Level.WARNING, "contextClassLoader is null, thread name is {0}, classs name is {1}.",
new Object[]{Thread.currentThread().getName(), name});
}
}
Class<?> clazz = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.core.plugin.subscribe.processor;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.service.dynamicconfig.common.DynamicConfigEvent;
import io.sermant.core.service.dynamicconfig.common.DynamicConfigListener;

Expand All @@ -43,7 +44,7 @@ public class IntegratedEventListenerAdapter implements DynamicConfigListener {
public IntegratedEventListenerAdapter(ConfigProcessor processor, String rawGroup) {
this.processor = processor;
this.rawGroup = rawGroup;
this.classLoader = Thread.currentThread().getContextClassLoader();
this.classLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
}

@Override
Expand All @@ -54,7 +55,7 @@ public void process(DynamicConfigEvent event) {

// The classloader at subscription time may not be the same as the classloader at listener configuration
// time, so need to restore it
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader currentClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
processor.process(rawGroup, event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.core.utils;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;

import java.io.IOException;
Expand Down Expand Up @@ -111,7 +112,7 @@ public static Optional<Class<?>> loadClass(String className, ClassLoader classLo
public static Optional<Object> createInstance(String className, ClassLoader classLoader, Class<?>[] paramTypes) {
ClassLoader curClassLoader = classLoader;
if (curClassLoader == null) {
curClassLoader = Thread.currentThread().getContextClassLoader();
curClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
}
try {
final Class<?> clazz = curClassLoader.loadClass(className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.core.utils;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;

import java.lang.reflect.AccessibleObject;
Expand Down Expand Up @@ -166,7 +167,7 @@ private static Optional<Class<?>> loadClass(String className) {
return Optional.empty();
}
return CLASS_CACHE.computeIfAbsent(className, value -> {
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
try {
return Optional.ofNullable(contextClassLoader.loadClass(className));
} catch (ClassNotFoundException ignored) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.sermant.implement.config;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.exception.SermantRuntimeException;

import org.yaml.snakeyaml.LoaderOptions;
Expand All @@ -35,7 +36,7 @@ public class SermantYamlConstructor extends Constructor {
*/
public SermantYamlConstructor() {
super(Object.class, new LoaderOptions());
loader = Thread.currentThread().getContextClassLoader();
loader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.auth.impl.NacosAuthLoginConstant;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.config.ConfigManager;
import io.sermant.core.service.dynamicconfig.config.DynamicConfig;
Expand Down Expand Up @@ -229,7 +230,7 @@ private Properties createProperties(String connectString, int sessionTimeout, St
* @throws NacosInitException Connect to Nacos failed
*/
private void createNacosClient(String connectString, Properties properties) {
ClassLoader tempClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader tempClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
nacosClient = new NacosClient(properties);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public String getRibbonLb(@RequestParam("serviceName") String serviceName) throw
if (!RIBBON_CLASS.equals(loadBalancerClient.getClass().getName())) {
return ERROR_RESPONSE;
}
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
final Class<?> ribbonClientClass = contextClassLoader.loadClass(RIBBON_CLASS);
final Field clientField = ReflectionUtils.findField(ribbonClientClass, "clientFactory");
if (clientField == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.dynamic.config.inject;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.plugin.config.PluginConfigManager;
import io.sermant.core.service.inject.ClassInjectDefine;
import io.sermant.core.utils.ClassUtils;
Expand All @@ -42,6 +43,6 @@ public Plugin plugin() {
@Override
public boolean canInject() {
return PluginConfigManager.getPluginConfig(DynamicConfiguration.class).isEnableDynamicConfig()
&& ClassUtils.loadClass(REFRESH_CLASS, Thread.currentThread().getContextClassLoader()).isPresent();
&& ClassUtils.loadClass(REFRESH_CLASS, ClassLoaderManager.getContextClassLoaderOrUserClassLoader()).isPresent();

Check failure on line 46 in sermant-plugins/sermant-dynamic-config/dynamic-config-plugin/src/main/java/io/sermant/dynamic/config/inject/DynamicClassInjectDefine.java

View workflow job for this annotation

GitHub Actions / Checkstyle

[Checkstyle Check] reported by reviewdog 🐶 Line is longer than 120 characters (found 128). Raw Output: /home/runner/work/Sermant/Sermant/./sermant-plugins/sermant-dynamic-config/dynamic-config-plugin/src/main/java/io/sermant/dynamic/config/inject/DynamicClassInjectDefine.java:46:0: error: Line is longer than 120 characters (found 128). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.dynamic.config.interceptors;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.service.ServiceManager;
Expand Down Expand Up @@ -94,7 +95,7 @@ private boolean isHasMethodLoadSpringFactories() {

private void injectConfigurationsWithLowVersion(Object result, String factoryName) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
if (result instanceof List) {
final List<String> convertedResult = (List<String>) result;
CLASS_DEFINES.forEach(classInjectDefine -> {
Expand All @@ -108,7 +109,7 @@ private void injectConfigurationsWithLowVersion(Object result, String factoryNam

private void injectConfigurations(Object result) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
final boolean isMultiValueMap = result instanceof MultiValueMap;
if (result instanceof Map) {
// spring 高版本处理, 针对List其为不可变list,需做一层处理
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.flowcontrol.common.handler.retry;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.config.PluginConfigManager;
import io.sermant.core.service.xds.entity.XdsRetryPolicy;
Expand Down Expand Up @@ -57,7 +58,8 @@ protected final Class<? extends Throwable>[] findClass(String[] classNames) {
final List<Class<?>> result = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
result.add(Class.forName(className, false, Thread.currentThread().getContextClassLoader()));
result.add(Class.forName(className, false,
ClassLoaderManager.getContextClassLoaderOrUserClassLoader()));
} catch (ClassNotFoundException exception) {
LoggerFactory.getLogger().info(String.format(Locale.ENGLISH,
"Can not find retry exception class %s", className));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.flowcontrol.config;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -101,7 +102,7 @@ private boolean isHasMethodLoadSpringFactories() {

private void injectConfigurationsWithLowVersion(Object result, String factoryName) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
if (result instanceof List) {
final List<String> convertedResult = (List<String>) result;
CLASS_DEFINES.forEach(classInjectDefine -> {
Expand All @@ -115,7 +116,7 @@ private void injectConfigurationsWithLowVersion(Object result, String factoryNam

private void injectConfigurations(Object result) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
final boolean isMultiValueMap = result instanceof MultiValueMap;
if (result instanceof Map) {
// Spring high version processing, for List, which is an immutable list, a layer of processing is required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.flowcontrol.inject;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.service.inject.ClassInjectDefine;
import io.sermant.core.utils.ClassUtils;

Expand Down Expand Up @@ -53,6 +54,8 @@ public Plugin plugin() {
}

private boolean isLoadedClass(String className) {
return ClassUtils.loadClass(className, Thread.currentThread().getContextClassLoader(), true).isPresent();
return ClassUtils
.loadClass(className, ClassLoaderManager.getContextClassLoaderOrUserClassLoader(), true)
.isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.flowcontrol.retry;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.utils.ClassUtils;
import io.sermant.flowcontrol.retry.cluster.AlibabaDubboCluster;
Expand Down Expand Up @@ -70,7 +71,7 @@ protected ExecuteContext doAfter(ExecuteContext context) {
return context;
}
final Optional<Class<?>> retryInvokerClass;
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
if (APACHE_DUBBO_CLUSTER_CLASS_NAME.equals(type.getName())) {
ClassUtils.defineClass(
"io.sermant.flowcontrol.retry.cluster.ApacheDubboClusterInvoker", contextClassLoader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.loadbalancer.interceptor;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -117,7 +118,7 @@ private void fillSupportRules(String extensionLoaderClazz, String lbClassName) {
}
supportRules = new HashSet<>();
final Optional<Class<?>> lbClazz = ClassUtils
.loadClass(lbClassName, Thread.currentThread().getContextClassLoader(), true);
.loadClass(lbClassName, ClassLoaderManager.getContextClassLoaderOrUserClassLoader(), true);
if (!lbClazz.isPresent()) {
return;
}
Expand All @@ -141,7 +142,7 @@ private void fillSupportRules(String extensionLoaderClazz, String lbClassName) {
}

private boolean isAlibaba() {
return ClassUtils.loadClass(ALIBABA_LOADER, Thread.currentThread().getContextClassLoader(), false)
return ClassUtils.loadClass(ALIBABA_LOADER, ClassLoaderManager.getContextClassLoaderOrUserClassLoader(), false)
.isPresent();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.sermant.loadbalancer.interceptor;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -101,7 +102,7 @@ private boolean isHasMethodLoadSpringFactories() {

private void injectConfigurationsWithLowVersion(Object result, String factoryName) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
if (result instanceof List) {
final List<String> convertedResult = (List<String>) result;
CLASS_DEFINES.forEach(classInjectDefine -> {
Expand All @@ -115,7 +116,7 @@ private void injectConfigurationsWithLowVersion(Object result, String factoryNam

private void injectConfigurations(Object result) {
final ClassInjectService service = ServiceManager.getService(ClassInjectService.class);
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
final boolean isMultiValueMap = result instanceof MultiValueMap;
if (result instanceof Map) {
// Spring high version processing, for List, which is an immutable list, a layer of processing is required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.IRule;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -67,7 +68,7 @@ public class RibbonLoadBalancerInterceptor extends AbstractInterceptor {

private final Function<RibbonLoadbalancerType, Optional<AbstractLoadBalancerRule>> ruleCreator = type -> {
final String clazzName = type.getClazzName();
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
try {
final Class<?> ruleClazz = contextClassLoader.loadClass(clazzName);
return Optional.of((AbstractLoadBalancerRule) ruleClazz.newInstance());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.sermant.dubbo.registry.utils;

import io.sermant.core.classloader.ClassLoaderManager;
import io.sermant.core.common.LoggerFactory;
import io.sermant.core.utils.ClassLoaderUtils;
import io.sermant.dubbo.registry.cache.DubboCache;
Expand Down Expand Up @@ -100,7 +101,7 @@ private ReflectUtils() {
* @return Host class
*/
public static Optional<Class<?>> defineClass(String className) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
try {
return Optional.of(ClassLoaderUtils.defineClass(className, contextClassLoader,
ClassLoaderUtils.getClassResource(ReflectUtils.class.getClassLoader(), className)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private NamingServiceUtils() {
public static NamingService buildNamingService(Map<String, String> parameters, NacosRegisterConfig registerConfig,
RegisterServiceCommonConfig commonConfig) {
Properties nacosProperties = buildNacosProperties(parameters, registerConfig, commonConfig);
ClassLoader tempClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader tempClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
Thread.currentThread().setContextClassLoader(NamingServiceUtils.class.getClassLoader());
try {
return NacosFactory.createNamingService(nacosProperties);
Expand Down
Loading

0 comments on commit 41b4113

Please sign in to comment.