Skip to content

Commit

Permalink
*fix spi classloader
Browse files Browse the repository at this point in the history
Signed-off-by: provenceee <[email protected]>
  • Loading branch information
provenceee committed Nov 20, 2024
1 parent bcb18a4 commit 059e4b0
Show file tree
Hide file tree
Showing 23 changed files with 80 additions and 27 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 @@ -87,6 +89,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 com.huaweicloud.sermant.core.plugin.classloader;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.config.ConfigManager;
import com.huaweicloud.sermant.core.plugin.agent.config.AgentConfig;
Expand Down Expand Up @@ -112,9 +113,16 @@ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundExce
// 无法从Sermant搜索路径中找到类,则尝试通过线程绑定的局部类加载器加载
if (clazz == null) {
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});
}
}

// 确保局部类加载器不是当前类加载器,否则会stackoverflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.huaweicloud.sermant.core.utils;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.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 com.huaweicloud.sermant.core.utils;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.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 @@ -19,6 +19,7 @@

import com.huawei.dynamic.config.DynamicConfiguration;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;
import com.huaweicloud.sermant.core.service.inject.ClassInjectDefine;
import com.huaweicloud.sermant.core.utils.ClassUtils;
Expand All @@ -43,6 +44,7 @@ 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.huawei.dynamic.config.interceptors;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.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 @@ -20,6 +20,7 @@
import com.huawei.flowcontrol.common.config.FlowControlConfig;
import com.huawei.flowcontrol.common.support.ReflectMethodCacheSupport;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;

Expand Down Expand Up @@ -54,7 +55,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 com.huawei.flowcontrol.config;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -100,7 +101,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 @@ -114,7 +115,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 com.huawei.flowcontrol.inject;

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

Expand Down Expand Up @@ -53,6 +54,7 @@ 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 @@ -20,6 +20,7 @@
import com.huawei.flowcontrol.retry.cluster.ClusterInvokerCreator;
import com.huawei.flowcontrol.service.InterceptorSupporter;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.utils.ClassUtils;

Expand Down Expand Up @@ -67,7 +68,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(
"com.huawei.flowcontrol.retry.cluster.ApacheDubboClusterInvoker", contextClassLoader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.huawei.flowcontrol.common.handler.retry.policy.RetryPolicy;
import com.huawei.flowcontrol.service.InterceptorSupporter;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.utils.ReflectUtils;
Expand Down Expand Up @@ -98,7 +99,7 @@ private Optional<Object> buildResult(Object lastServer, String responseClassName
if (defaultResponseClazz == null) {
return Optional.empty();
}
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final ClassLoader contextClassLoader = ClassLoaderManager.getContextClassLoaderOrUserClassLoader();
try {
final Class<?> clazz = contextClassLoader.loadClass(defaultResponseClazz);
final Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(ServiceInstance.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.huaweicloud.loadbalancer.constants.DubboUrlParamsConstants;
import com.huaweicloud.loadbalancer.rule.LoadbalancerRule;
import com.huaweicloud.loadbalancer.rule.RuleManager;
import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -110,7 +111,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 @@ -134,7 +135,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 com.huaweicloud.loadbalancer.interceptor;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
Expand Down Expand Up @@ -100,7 +101,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 @@ -114,7 +115,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 @@ -22,6 +22,7 @@
import com.huaweicloud.loadbalancer.config.LoadbalancerConfig;
import com.huaweicloud.loadbalancer.config.RibbonLoadbalancerType;
import com.huaweicloud.loadbalancer.rule.RuleManager;
import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.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 @@ -19,6 +19,7 @@
import com.huawei.dubbo.registry.cache.DubboCache;
import com.huawei.dubbo.registry.constants.Constant;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.utils.ClassLoaderUtils;

Expand Down Expand Up @@ -77,7 +78,7 @@ private ReflectUtils() {
* @return 宿主类
*/
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 @@ -21,6 +21,7 @@
import com.huawei.registry.utils.CommonUtils;
import com.huawei.registry.utils.HostUtils;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;
import com.huaweicloud.sermant.core.plugin.service.PluginServiceManager;
Expand Down Expand Up @@ -120,7 +121,8 @@ private Optional<Object> tryGetInetUtils() {

private Optional<Object> tryGetInetUtilsByClazz() {
final Optional<Class<?>> clazz = ClassUtils
.loadClass(INET_UTILS_CLASS, Thread.currentThread().getContextClassLoader(), false);
.loadClass(INET_UTILS_CLASS, ClassLoaderManager.getContextClassLoaderOrUserClassLoader(),
false);
if (!clazz.isPresent()) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import com.huawei.registry.config.RegisterConfig;

import com.huaweicloud.sermant.core.classloader.ClassLoaderManager;
import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;
import com.huaweicloud.sermant.core.service.inject.ClassInjectDefine;
import com.huaweicloud.sermant.core.utils.ClassUtils;
Expand Down Expand Up @@ -48,6 +49,7 @@ public Plugin plugin() {
* @return 是否被加载
*/
protected boolean isClassExistedOnCurrentClassLoader(String className) {
return ClassUtils.loadClass(className, Thread.currentThread().getContextClassLoader(), false).isPresent();
return ClassUtils.loadClass(className, ClassLoaderManager.getContextClassLoaderOrUserClassLoader(), false)
.isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.huawei.registry.inject;

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

Expand Down Expand Up @@ -52,6 +53,6 @@ public ClassInjectDefine[] requiredDefines() {
public boolean canInject() {
return super.canInject() && ClassUtils.loadClass(
"org.springframework.cloud.netflix.ribbon.SpringClientFactory",
Thread.currentThread().getContextClassLoader(), false).isPresent();
ClassLoaderManager.getContextClassLoaderOrUserClassLoader(), false).isPresent();
}
}
Loading

0 comments on commit 059e4b0

Please sign in to comment.