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.
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-Version: 1.0 Premain-Class: com.example.DynamicLoader Can-Redefine-Classes: true Can-Retransform-Classes: true
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
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>dynamic-loader</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Premain-Class>com.example.DynamicLoader</Premain-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build> </project>
java -javaagent:dynamic-loader.jar --add-opens java.base/java.lang=ALL-UNNAMED YourMainClass
public class MainApp { public static void main(String[] args) { // Classes from dynamically loaded jars are now available MyDynamicClass instance = new MyDynamicClass(); instance.doSomething(); } }
project/ │ ├── src/ │ └── main/ │ └── java/ │ └── com/ │ └── example/ │ └── DynamicLoader.java │ ├── libs/ │ ├── mylib1.jar │ └── mylib2.jar │ ├── pom.xml └── README.md