Table of Contents

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

<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>

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

Common Issues

Best Practices

Example Directory Structure

project/
│
├── src/
│   └── main/
│       └── java/
│           └── com/
│               └── example/
│                   └── DynamicLoader.java
│
├── libs/
│   ├── mylib1.jar
│   └── mylib2.jar
│
├── pom.xml
└── README.md

References