Operations 16 min read

Fixing SkyWalking ThreadPool Plugin Enhancement Failure by Making AgentClassLoader a Singleton

This article details the investigation of a SkyWalking thread‑pool plugin enhancement failure caused by multiple AgentClassLoader instances, explains the debugging steps, class‑loading behavior, and provides two practical solutions to ensure proper bytecode instrumentation for ThreadPoolExecutor in Java applications.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Fixing SkyWalking ThreadPool Plugin Enhancement Failure by Making AgentClassLoader a Singleton

The author reports a failure of the SkyWalking thread‑pool plugin where the traceId was empty in asynchronous tasks. After fixing the issue, the problem and its root cause are explained.

1. Background

The project uses SkyWalking agent 8.14.0 with Spring Boot 2.2.6.RELEASE on JDK 1.8. The apm-jdk-threadpool-plugin.jar is placed in the plugins directory, but during runtime the thread‑pool enhancement does not work, resulting in missing traceId values.

2. Investigation Process

2.1 Discovery about AgentClassLoader

Logs showed that the AgentClassLoader scanned the plugins directory twice, creating two separate instances. Debugging confirmed that one instance is created during the premain method and another when the first plugin class (an Interceptor) is loaded.

Because bytecode enhancement relies on the AgentClassLoader to load Interceptor classes, the duplicate instances caused the thread‑pool plugin to fail.

2.2 ThreadPoolExecutor class‑loading timing

Using -XX:+TraceClassLoading the author observed that ThreadPoolExecutor is loaded after the transformer registration, while core classes like Runnable and Thread are loaded before the agent, making them hard to enhance.

Further debugging showed that the first instantiation of ThreadPoolExecutor occurs inside SkyWalking's logging component ( FileWriter ), which is triggered by Spring's AutowiredAnnotationBeanPostProcessor . This creates a dependency on ThreadPoolExecutor during the transform phase, preventing a second transformation.

2.3 Hypothesis on JVM transform logic

The JVM appears to avoid re‑transforming a class B that is loaded as a dependency while class A is being transformed, to prevent recursive transform loops.

2.4 Summary of findings

The thread‑pool plugin fails only when other third‑party plugins are loaded before ThreadPoolExecutor , because the latter’s enhancement depends on the AgentClassLoader which is instantiated twice, leading to duplicate scanning and logging.

3. Solution

Make AgentClassLoader a singleton to avoid repeated plugin directory scans and the extra log dependency on ThreadPoolExecutor .

Remove the logging component ( FileWriter ) that creates a ThreadPoolExecutor dependency, replacing it with a simple thread‑loop implementation.

The first approach was rejected after discussion, so the second approach was adopted, using a custom thread loop instead of Timer / TimerTask to avoid future plugin conflicts.

4. Related Issues and Discussions

https://github.com/apache/skywalking/issues/9425

https://github.com/apache/skywalking/issues/9850

https://github.com/apache/skywalking/issues/10374

https://github.com/apache/skywalking/issues/10685

https://github.com/apache/skywalking/discussions/10207

https://github.com/apache/skywalking/discussions/9888

5. Closing Remarks

The author invites readers to like, share, and follow the article, and promotes a paid knowledge community for deeper Spring and micro‑service content.

InstrumentationAPMthreadpoolJavaAgentSkyWalkingAgentClassLoader
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.