alibaba / alibaba/one-java-agent
记录一个 ClassLoaderHandler 类加载问题排查
- Dominant language
- Java
- Stars
- 579
- Forks
- 128
- PR merge metrics
- No merged PRs in 30d
Description
在目前代码里,有一个 dubbo的示例,里面有一个 com.test.dubbo.DubboPluginClassLoaderHandler
```java
public class DubboPluginClassLoaderHandler implements ClassLoaderHandler {
@Override
public Class loadClass(String name) {
if (name.startsWith("com.test.dubbo")) {
try {
Class clazz = this.getClass().getClassLoader().loadClass(name);
return clazz;
} catch (Throwable e) {
e.printStackTrace();
}
}
return null;
}
}
```
显然它是为了保证 dubbo-test-plugin-common 下的测试类 `com.test.dubbo.RpcUtils` 能被其它ClassLoader正常加载。
---
当用户自己写了一个 dubbo 的测试,里面的代码是 `com.test.dubbo.EchoService` ,这里就出现问题了。
* package 和 DubboPluginClassLoaderHandler 里的重名了,导致应用的 `com.test.dubbo.EchoService` 会被 dubbo-plugin PluginClassLoader 加载。
* PluginClassLoader 目前的加载顺序,最终会向上调用 super 去查找,PluginClassLoader 的 parent 是启动 one-java-agent 的 ClassLoader 。
* 所以最终可能 `com.test.dubbo.EchoService` 是被 one-java-agent 的 ClassLoader 加载到。而并不是应用的 ClassLoader。
---
一个异常栈:
```
Thread [main] (Suspended (breakpoint at line 26 in AgentSpyImpl))
owns: Object (id=11559)
owns: OneAgentClassLoader (id=11560)
owns: PluginClassLoader (id=11561)
owns: Object (id=11562)
AgentSpyImpl.loadClass(String) line: 26
Launcher$AppClassLoader(ClassLoader).loadClass(String) line: 49
ClassLoader.defineClass1(String, byte[], int, int, ProtectionDomain, String) line: not available [native method]
Launcher$AppClassLoader(ClassLoader).defineClass(String, byte[], int, int, ProtectionDomain) line: 763
Launcher$AppClassLoader(SecureClassLoader).defineClass(String, byte[], int, int, CodeSource) line: 142
Launcher$AppClassLoader(URLClassLoader).defineClass(String, Resource) line: 468
URLClassLoader.access$100(URLClassLoader, String, Resource) line: 74
URLClassLoader$1.run() line: 369
URLClassLoader$1.run() line: 363
AccessController.doPrivileged(PrivilegedExceptionAction, AccessControlContext) line: not available [native method]
Launcher$AppClassLoader(URLClassLoader).findClass(String) line: 362
Launcher$AppClassLoader(ClassLoader).loadClass(String, boolean) line: 424
Launcher$AppClassLoader.loadClass(String, boolean) line: 349
OneAgentClassLoader(ClassLoader).loadClass(String, boolean) line: 411
PluginClassLoader(ClassLoader).loadClass(String, boolean) line: 411
PluginClassLoader.loadClass(String, boolean) line: 144
PluginClassLoader(ClassLoader).loadClass(String) line: 357
DubboPluginClassLoaderHandler.loadClass(String) line: 16
ClassLoaderHandlerManagerImpl.loadClass(String) line: 80
AgentSpyImpl.loadClass(String) line: 26
ReLaunchURLClassLoader(ClassLoader).loadClass(String) line: 49
Class.forName0(String, boolean, ClassLoader, Class) line: not available [native method]
Class.forName(String, boolean, ClassLoader) line: 348
ClassUtils.forName(String, ClassLoader) line: 280
ClassUtils.resolveClassName(String, ClassLoader) line: 320
ServiceClassPostProcessor.resolveClass(BeanDefinition) line: 361
ServiceClassPostProcessor.resolveClass(BeanDefinitionHolder) line: 353
ServiceClassPostProcessor.registerServiceBean(BeanDefinitionHolder, BeanDefinitionRegistry, DubboClassPathBeanDefinitionScanner) line: 279
ServiceClassPostProcessor.registerServiceBeans(Set, BeanDefinitionRegistry) line: 175
ServiceClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) line: 134
PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(Collection, BeanDefinitionRegistry) line: 275
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List) line: 125
AnnotationConfigApplicationContext(AbstractApplicationContext).invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) line: 706
AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 532
SpringApplication.refresh(ApplicationContext) line: 744
SpringApplication.refreshContext(ConfigurableApplicationContext) line: 391
SpringApplication.run(String...) line: 312
SpringApplication.run(Class[], String[]) line: 1215
SpringApplication.run(Class, String...) line: 1204
Application.main(String[]) line: 33
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 498
LaunchRunner.run() line: 38
Thread.run() line: 748
```
---
TODO
* 仔细定义启动 one-java-agent的 ClassLoader 和 PluginClassLoader 的行为
* 使用 ClassLoaderHandler 时要非常小心
Contributor guide
No contributing guide indexed for this repository
Research direction
Trace the loading path through DubboPluginClassLoaderHandler.loadClass, ClassLoaderHandlerManagerImpl.loadClass, AgentSpyImpl.loadClass, PluginClassLoader, and OneAgentClassLoader using the provided stack trace. Reproduce the com.test.dubbo.EchoService collision and define the intended class-loader behavior; done means the behavior and safe use of ClassLoaderHandler are resolved and documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100