Skip to content

using inst.appendToSystemClassLoaderSearch to add custom dependency to system class loader #577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ private byte[] getBytes(String name, ClassLoader loader) throws IOException {
return locator.locate(name).resolve();
}

public void appendToSystemClassLoaderSearch(String jarPackageName) {
appendToClassLoaderSearch(jarPackageName, null);
}
public void appendToClassLoaderSearch(String jarPackageName, ClassLoader loader) {
List<String> filePathList = THIRD_PARTY_NESTED_JARS_PATH_MAP.get(jarPackageName);
if (CollectionUtil.isEmpty(filePathList)) {
Expand All @@ -130,7 +133,11 @@ public void appendToClassLoaderSearch(String jarPackageName, ClassLoader loader)
for (String filePath : filePathList) {
JarEntry jarEntry = agentJarFile.getJarEntry(filePath);
File extractNestedJar = JarUtils.extractNestedJar(agentJarFile, jarEntry, filePath);
JarUtils.appendToClassLoaderSearch(loader, extractNestedJar);
if (loader == null) {
JarUtils.appendToSystemClassLoaderSearch(extractNestedJar);
}else{
JarUtils.appendToClassLoaderSearch(loader, extractNestedJar);
}
}
} catch (Exception ex) {
System.err.printf("appendToClassLoaderSearch failed, jarPackageName: %s%n", jarPackageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarUtils {
private static Method addURL;
private static final File TMP_FILE = new File(AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("java.io.tmpdir")));
private static final String AREX_TEMP_DIR = TMP_FILE.getAbsolutePath() + File.separator + "arex";
public static Consumer<File> addJarToSystemClassLoader = file -> {
};

static {
try {
Expand All @@ -28,10 +31,11 @@ public class JarUtils {
System.err.println("Failed to get addURL method from URLClassLoader");
}
}

public static File extractNestedJar(JarFile file, JarEntry entry, String entryName) throws IOException {
File outputFile = createFile(AREX_TEMP_DIR + File.separator + entryName);
try(InputStream inputStream = file.getInputStream(entry);
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
try (InputStream inputStream = file.getInputStream(entry);
FileOutputStream outputStream = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
Expand All @@ -53,6 +57,19 @@ private static File createFile(String path) throws IOException {
return file;
}

/**
* Java Instrumentation.appendToSystemClassLoaderSearch() method is compatible across JDK versions, including JDK 8 through JDK 17. Here’s a detailed breakdown of its compatibility:
* 1. JDK 8 Compatibility
* • The appendToSystemClassLoaderSearch() method was introduced as part of the Java Instrumentation API in JDK 6. This means it is fully available and compatible with JDK 8.
* • It allows you to append JARs to the system class loader’s search path, ensuring that classes within those JARs can be loaded by the system class loader.
* 2. JDK 9+ (including JDK 17) Compatibility
* • With JDK 9, the module system (Project Jigsaw) was introduced, which brought significant changes to class loading and the organization of Java’s internal APIs.
* • Despite these changes, appendToSystemClassLoaderSearch() remains compatible and continues to work as expected in JDK 9 and later, including JDK 17. It can still be used to add JARs to the classpath of the system class loader.
*/
public static void appendToSystemClassLoaderSearch(File jarFile) {
addJarToSystemClassLoader.accept(jarFile);
}

/**
* tomcat jdk <= 8, classLoader is ParallelWebappClassLoader, ClassLoader.getSystemClassLoader() is Launcher$AppClassLoader
* jdk > 8, classLoader is ParallelWebappClassLoader, ClassLoader.getSystemClassLoader() is ClassLoaders$AppClassLoader
Expand All @@ -69,7 +86,7 @@ public static void appendToClassLoaderSearch(ClassLoader classLoader, File jarFi
*/
ClassLoader urlClassLoader = ClassLoader.getSystemClassLoader();
if (!(urlClassLoader instanceof URLClassLoader)) {
try (URLClassLoader tempClassLoader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}, urlClassLoader)) {
try (URLClassLoader tempClassLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}, urlClassLoader)) {
addURL.invoke(tempClassLoader, jarFile.toURI().toURL());
}
} else {
Expand Down
7 changes: 7 additions & 0 deletions arex-agent/src/main/java/io/arex/agent/ArexAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ private static void init(Instrumentation inst, String agentArgs) {
*/
installBootstrapJar(inst);
AgentInitializer.initialize(inst, getJarFile(ArexAgent.class), agentArgs, ArexAgent.class.getClassLoader());
io.arex.agent.bootstrap.util.JarUtils.addJarToSystemClassLoader = file -> {
try {
inst.appendToSystemClassLoaderSearch(new JarFile(file, false));
} catch (Exception e) {
System.out.printf("%s [AREX] Agent add jar to system classloader error, stacktrace: %s%n", getCurrentTime(), e);
}
};
} catch (Exception ex) {
System.out.printf("%s [AREX] Agent initialize error, stacktrace: %s%n", getCurrentTime(), ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ private static void addEnterLog() {
*/
private static void initSerializer(ClassLoader contextClassLoader) {
if (!existJacksonDependency) {
AdviceClassesCollector.INSTANCE.appendToClassLoaderSearch("jackson",
contextClassLoader);
AdviceClassesCollector.INSTANCE.appendToSystemClassLoaderSearch("jackson");
}
final List<StringSerializable> serializableList = ServiceLoader.load(StringSerializable.class, contextClassLoader);
Serializer.builder(serializableList).build();
Expand Down