This is a showcase on how to extend a Spring Boot application with plugins packaged as jar files.
A custom classloader PluginClassloader
has been created and plugged into SpringApplication. This makes Spring scan and load all classes and resources using this classloader. The main feature of this classloader is that it keeps references to jars users uploaded and allows loading classes packaged within them. The list of references (jars) can be refreshed at any time, in runtime. Remember, the classloader doesn’t store classes, it only loads them - JVM stores them. Application context reload is achieved by using spring actuator. That way, there’s a short period of platform unavailability, but the process continues to run. Restart can only be observed by a short period of endpoint unavailability.
Rather than just saying what’s on the classpath let’s take it a step further and check which HTTP endpoints are available in the app, and by doing that - verify that the Spring based plugin (with @Controller
inside) is loaded.
-
Start by checking what’s available before you upload anything
curl 'http:https://localhost:8080/introspect/endpoints'
-
Upload a plugin with spring
@Controller
inside
curl --request POST 'http:https://localhost:8080/plugins/upload' --form 'file=@"spring-plugin/target/spring-plugin-0.0.1-SNAPSHOT.jar"'
-
Restart the app context (remember, the process keeps running)
curl --request POST 'http:https://localhost:8080/actuator/restart'
-
Check what’s available once again. You should be seeing a new endpoint
"/springController"
which you can call with
curl 'http:https://localhost:8080/springController'
This should return HTTP 200 with contentHello from SpringController!
What this approach gives you is that you don’t have to have the plugin jars on the filesystem at the moment the app is started. When java -jar
is run, you can fetch the plugins from some external location, copy them over onto the filesystem and then execute SpringApplication.run(args)
. This makes your platform cloud ready, and you don’t have to worry about which plugins have to be in the Docker image.