I have a Spring Boot application which copies external JAR files to a folder, depending on certain conditions. These JARs can contain many Spring components (i.e. classes annotated or meta-annotated with @Component
) and the Spring application should be able scan and instantiate for these beans. Is it possible, based on certain conditions, to dynamically load the contents of the JAR files and make them available to the Spring application context? I am fully aware of the security implications this has.
I have read about the different types of Launcher
s which Spring provides for its executable JAR format, such as JarLauncher
and PropertiesLauncher
, but it looks like that these launchers do not detect changes to the classpath, but instead only scan the directories once for JAR files.
The following simple application demonstrates the problem:
// .../Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
System.out.println("Please copy JAR files and press Enter ...");
System.in.read();
SpringApplication.run(Application.class, args);
}
}
Replace the default JarLauncher
with PropertiesLauncher
:
// build.gradle
tasks.named('bootJar') {
manifest {
attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher',
'Start-Class': 'com.example.customlauncher.Application'
}
}
Specify the location to the external JARs in the properties file of the PropertiesLauncher
:
# .../resources/loader.properties
loader.path=file:/path/to/dir
The application is a Spring Initializer Gradle application and packaged by running the bootJar
task: ./gradlew bootJar
.
It is then started with the following command:
java -jar build/libs/customlauncher-0.0.1-SNAPSHOT.jar
This works if the JAR file is already present at the specified location (/path/to/dir
), but it does not work if the java
command is executed while the directory is empty and the JAR file is then copied while the app waits for the user to copy the files and press Enter ↲.
There are a couple of related questions, but it looks like they all assume that the JAR files already exist at the time of starting the JVM:
- How to put a directory first on the classpath with Spring Boot?
- Spring Boot Executable Jar with Classpath
- SpringBoot external jar not load
Is there a way to achieve this without too many awkard hacks? Or is recommended to utilize something like OSGi? Am I looking at this completely wrong and there is a better way to have JARs on the classpath that do not need always need loading (if the JAR is "disabled", it should not be loaded/compiled by the JVM, should not be picked up by Spring, etc.)?