User Tools

Site Tools


java:dynamic-class-loader

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

  • 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

java/dynamic-class-loader.txt · Last modified: 2025/01/18 00:08 by odefta