Create a shared parent classloader
MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java
@@ -38,10 +38,13 @@ public class Agent {
}
// fields must be managed under class lock
+ private static ClassLoader PARENT_CLASSLOADER = null;
+ private static ClassLoader BOOTSTRAP_PROXY = null;
private static ClassLoader AGENT_CLASSLOADER = null;
private static ClassLoader JMXFETCH_CLASSLOADER = null;
public static void start(final Instrumentation inst, final URL bootstrapURL) {
+ createParentClassloader(bootstrapURL);
startDatadogAgent(inst, bootstrapURL);
final boolean appUsingCustomLogManager = isAppUsingCustomLogManager();
@@ -160,6 +163,27 @@ public class Agent {
}
}
+ private static synchronized void createParentClassloader(final URL bootstrapURL) {
+ if (PARENT_CLASSLOADER == null) {
+ try {
+ if (isJavaBefore9()) {
+ PARENT_CLASSLOADER = null; // bootstrap
+ } else {
+ // platform classloader is parent of system in java 9+
+ PARENT_CLASSLOADER = getPlatformClassLoader();
+ }
+
+ final Class<?> loaderClass =
+ ClassLoader.getSystemClassLoader()
+ .loadClass("datadog.trace.bootstrap.DatadogClassLoader$BootstrapClassLoaderProxy");
+ final Constructor constructor = loaderClass.getDeclaredConstructor(URL.class);
+ BOOTSTRAP_PROXY = (ClassLoader) constructor.newInstance(bootstrapURL);
+ } catch (final Throwable ex) {
+ log.error("Throwable thrown creating parent classloader", ex);
+ }
+ }
+ }
+
private static synchronized void startDatadogAgent(
final Instrumentation inst, final URL bootstrapURL) {
if (AGENT_CLASSLOADER == null) {
@@ -244,19 +268,15 @@ public class Agent {
*/
private static ClassLoader createDatadogClassLoader(
final String innerJarFilename, final URL bootstrapURL) throws Exception {
- final ClassLoader agentParent;
- if (isJavaBefore9()) {
- agentParent = null; // bootstrap
- } else {
- // platform classloader is parent of system in java 9+
- agentParent = getPlatformClassLoader();
- }
final Class<?> loaderClass =
ClassLoader.getSystemClassLoader().loadClass("datadog.trace.bootstrap.DatadogClassLoader");
final Constructor constructor =
- loaderClass.getDeclaredConstructor(URL.class, String.class, ClassLoader.class);
- return (ClassLoader) constructor.newInstance(bootstrapURL, innerJarFilename, agentParent);
+ loaderClass.getDeclaredConstructor(
+ URL.class, String.class, ClassLoader.class, ClassLoader.class);
+ return (ClassLoader)
+ constructor.newInstance(
+ bootstrapURL, innerJarFilename, BOOTSTRAP_PROXY, PARENT_CLASSLOADER);
}
private static ClassLoader getPlatformClassLoader()

MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
@@ -21,7 +21,7 @@ public class DatadogClassLoader extends URLClassLoader {
// adds a jar to the bootstrap class lookup, but not to the resource lookup.
// As a workaround, we keep a reference to the bootstrap jar
// to use only for resource lookups.
- private final BootstrapClassLoaderProxy bootstrapProxy;
+ private final ClassLoader bootstrapProxy;
/**
* Construct a new DatadogClassLoader
*
@@ -31,14 +31,13 @@ public class DatadogClassLoader extends URLClassLoader {
* 9+.
*/
public DatadogClassLoader(
- final URL bootstrapJarLocation, final String internalJarFileName, final ClassLoader parent) {
+ final URL bootstrapJarLocation,
+ final String internalJarFileName,
+ final ClassLoader bootstrapProxy,
+ final ClassLoader parent) {
super(new URL[] {}, parent);
- // some tests pass null
- bootstrapProxy =
- bootstrapJarLocation == null
- ? new BootstrapClassLoaderProxy(new URL[0])
- : new BootstrapClassLoaderProxy(new URL[] {bootstrapJarLocation});
+ this.bootstrapProxy = bootstrapProxy;
try {
// The fields of the URL are mostly dummy. InternalJarURLHandler is the only important
@@ -78,7 +77,7 @@ public class DatadogClassLoader extends URLClassLoader {
return findLoadedClass(className) != null;
}
- public BootstrapClassLoaderProxy getBootstrapProxy() {
+ public ClassLoader getBootstrapProxy() {
return bootstrapProxy;
}
@@ -93,8 +92,12 @@ public class DatadogClassLoader extends URLClassLoader {
ClassLoader.registerAsParallelCapable();
}
- public BootstrapClassLoaderProxy(final URL[] urls) {
- super(urls, null);
+ public BootstrapClassLoaderProxy(final URL url) {
+ super(new URL[] {url}, null);
+ }
+
+ public BootstrapClassLoaderProxy() {
+ super(new URL[0], null);
}
@Override

MODIFY
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Utils.java
dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Utils.java
@@ -5,7 +5,6 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import datadog.trace.bootstrap.DatadogClassLoader;
import datadog.trace.bootstrap.DatadogClassLoader.BootstrapClassLoaderProxy;
import java.lang.reflect.Method;
-import java.net.URL;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDefinition;
@@ -15,7 +14,7 @@ public class Utils {
private static Method findLoadedClassMethod = null;
private static final BootstrapClassLoaderProxy unitTestBootstrapProxy =
- new BootstrapClassLoaderProxy(new URL[0]);
+ new BootstrapClassLoaderProxy();
static {
try {
@@ -31,7 +30,7 @@ public class Utils {
}
/** Return a classloader which can be used to look up bootstrap resources. */
- public static BootstrapClassLoaderProxy getBootstrapProxy() {
+ public static ClassLoader getBootstrapProxy() {
if (getAgentClassLoader() instanceof DatadogClassLoader) {
return ((DatadogClassLoader) getAgentClassLoader()).getBootstrapProxy();
} else {
@@ -86,10 +85,10 @@ public class Utils {
/** @return The current stack trace with multiple entries on new lines. */
public static String getStackTraceAsString() {
- StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
- StringBuilder stringBuilder = new StringBuilder();
- String lineSeparator = System.getProperty("line.separator");
- for (StackTraceElement element : stackTrace) {
+ final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ final StringBuilder stringBuilder = new StringBuilder();
+ final String lineSeparator = System.getProperty("line.separator");
+ for (final StackTraceElement element : stackTrace) {
stringBuilder.append(element.toString());
stringBuilder.append(lineSeparator);
}

MODIFY
dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java
dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/SpockRunner.java
@@ -2,6 +2,7 @@ package datadog.trace.agent.test;
import com.google.common.reflect.ClassPath;
import datadog.trace.agent.test.utils.ClasspathUtils;
+import datadog.trace.bootstrap.DatadogClassLoader.BootstrapClassLoaderProxy;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -142,7 +143,8 @@ public class SpockRunner extends Sputnik {
.appendToBootstrapClassLoaderSearch(new JarFile(bootstrapJar));
// Utils cannot be referenced before this line, as its static initializers load bootstrap
// classes (for example, the bootstrap proxy).
- datadog.trace.agent.tooling.Utils.getBootstrapProxy().addURL(bootstrapJar.toURI().toURL());
+ ((BootstrapClassLoaderProxy) datadog.trace.agent.tooling.Utils.getBootstrapProxy())
+ .addURL(bootstrapJar.toURI().toURL());
} catch (final IOException e) {
throw new RuntimeException(e);
}

Create a shared parent classloader