====== Dynamic Classpath Loading with Java Instrumentation ======
===== Overview =====
Starting with Java 9, the recommended way to modify the classpath at runtime is using Java Instrumentation. This approach works with the Java Module System and is production-ready.
===== Implementation =====
==== Basic Agent Class ====
package com.example;
import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;
public class DynamicLoader {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
try {
// Load specific jar
inst.appendToSystemClassLoaderSearch(new JarFile("libs/mylib.jar"));
// Or load all jars from a directory
File libDir = new File("libs");
if (libDir.isDirectory()) {
for (File jar : libDir.listFiles((dir, name) -> name.endsWith(".jar"))) {
inst.appendToSystemClassLoaderSearch(new JarFile(jar));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
==== MANIFEST.MF ====
Manifest-Version: 1.0
Premain-Class: com.example.DynamicLoader
Can-Redefine-Classes: true
Can-Retransform-Classes: true
===== Building =====
==== Without Maven ====
javac DynamicLoader.java
mkdir META-INF
# Create MANIFEST.MF with content above
jar cfm dynamic-loader.jar META-INF/MANIFEST.MF com/example/DynamicLoader.class
==== With Maven ====
4.0.0
com.example
dynamic-loader
1.0-SNAPSHOT
17
17
org.apache.maven.plugins
maven-jar-plugin
3.2.0
true
com.example.DynamicLoader
true
true
===== Running =====
==== Basic Usage ====
java -javaagent:dynamic-loader.jar --add-opens java.base/java.lang=ALL-UNNAMED YourMainClass
==== Example Main Class ====
public class MainApp {
public static void main(String[] args) {
// Classes from dynamically loaded jars are now available
MyDynamicClass instance = new MyDynamicClass();
instance.doSomething();
}
}
===== Important Notes =====
* The agent must be loaded before the main class
* The --add-opens argument is required for Java 9+
* The agent jar must be accessible when starting the JVM
* Error handling should be implemented for production use
===== Common Issues =====
* **ClassNotFoundException**: Verify jar path and manifest
* **SecurityException**: Check --add-opens arguments
* **InvalidJarException**: Ensure jar files are valid
===== Best Practices =====
* Log all loaded jars
* Implement proper error handling
* Document the loading process
* Test with all target Java versions
* Consider security implications
===== Example Directory Structure =====
project/
│
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── DynamicLoader.java
│
├── libs/
│ ├── mylib1.jar
│ └── mylib2.jar
│
├── pom.xml
└── README.md
===== References =====
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.instrument/java/lang/instrument/Instrumentation.html|Java Instrumentation API]]
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/jar/JarFile.html|JarFile Documentation]]