How to Dynamically Load External JARs into Spring Boot at Runtime

This guide explains step‑by‑step how to load external JAR files into the JVM, configure Spring Boot to recognize them, and choose among four practical solutions—including classpath expansion, Spring Boot loader.path, custom class loaders, and JVM boot classpath tweaks—while highlighting their pros, cons, and required Maven settings.

Architect's Must-Have
Architect's Must-Have
Architect's Must-Have
How to Dynamically Load External JARs into Spring Boot at Runtime

Implementation Plan

Implementation is simple, just two steps: load the class into the JVM and let Spring scan the class.

Load the class into the JVM.

Make Spring scan the class.

Sometimes the source code of various Java frameworks, especially the Spring family, creates a big understanding barrier; therefore, it is better to clarify the overall implementation steps first.

Load Class into JVM

Assume the JAR to load is located at /user/local/java/plugins. There are several ways to achieve the first step:

Expand -cp of AppClassLoader to load external JARs.

Use Spring Boot launch parameter loader.path.

Customize a classloader to load JARs from a specific location.

Options 1 and 3 are JDK‑provided solutions; option 2 is a Spring Boot extension.

Option 1: Expand -cp via AppClassLoader

You can use classpath to specify the class loading path, but its effect is conditional—it works only when the JAR is started via its Main function or by running the JAR directly.

Spring Boot’s packaged JAR contains a MANIFEST.MF like this:

Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.2.2
Build-Jdk-Spec: 18
Implementation-Title: intelligent-soul
Implementation-Version: 0.0.1-SNAPSHOT
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.test.MyApplication
Spring-Boot-Version: 2.6.15
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx

Therefore the application must be started with Main-Class set to JarLauncher, not the usual JAR launch command.

java -cp /user/local/java/plugins org.springframework.boot.loader.JarLauncher

Pros: simple implementation.

Cons: every JAR uses the same start command, making it hard to distinguish.

Option 2: Use Spring Boot’s loader.path with java -jar

Because Spring Boot programs are usually packaged as JARs and started with java -jar boot.jar, the -cp option is ineffective. You can use loader.path to specify additional classpath, but it works only under certain conditions.

Spring Boot’s default Main-Class is JarLauncher. To make loader.path effective, set Main-Class to PropertiesLauncher in Maven configuration:

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <!-- Exclude system‑scope dependencies when packaging -->
        <includeSystemScope>false</includeSystemScope>
        <!-- Enable loader.path by setting layout to ZIP -->
        <layout>ZIP</layout>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>repackage</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
  <finalName>Test</finalName>
</build>

Layout options and their corresponding Main-Class values are:

JAR : Main-Class: org.springframework.boot.loader.JarLauncher WAR : Main-Class: org.springframework.boot.loader.WarLauncher ZIP :

Main-Class: org.springframework.boot.loader.PropertiesLauncher

MODULE : packages all dependencies (excluding provided scope) without Spring Boot launchers.

NONE : packages all dependencies but excludes any Spring Boot launcher.

Note that the same program packaged as PropertiesLauncher (≈20 s) starts much slower than with JarLauncher (≈8 s).

Option 3: Custom ClassLoader

This approach invokes a custom class loader at a certain point during program startup to load JARs from a fixed directory or an environment‑variable path, offering high customization but making the exact timing harder to control.

// Example invocation of a custom class loader
SpringApplication.run(SpringBootDemo.class, args);

Option 4: Use -Xbootclasspath/a or java.ext.dirs

Alters the system class loader’s behavior; this method is unsafe and not recommended.

Scanning Loaded Classes into the Spring Container

For business JAR classes, specify the base package in Spring Boot, e.g., com.demo, so Spring scans them automatically:

@SpringBootApplication(scanBasePackages = {"com.demo"})
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

If the package prefix does not match, configure spring.factories under META-INF to auto‑configure the classes, for example with MyBatis‑Plus:

# Auto Configure
org.springframework.boot.env.EnvironmentPostProcessor=\
  com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
JavaJVMSpring BootCustom ClassLoaderclass loading
Architect's Must-Have
Written by

Architect's Must-Have

Professional architects sharing high‑quality architecture insights. Covers high‑availability, high‑performance, high‑stability designs, big data, machine learning, Java, system, distributed and AI architectures, plus internet‑driven architectural adjustments and large‑scale practice. Open to idea‑driven, sharing architects for exchange and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.