-
By: Eric Liu
-
Mentors: Zeping Bai, Zhiyuan Ju, ZhengSong Tu (tzssangglass)
This project's aim was to improve upon the current apisix-java-plugin-runner design. APISIX is an API Gateway that provides traffic management (load balancing, authorization, security, etc). Users can develop their own custom plugins, however, the current development process for Java plugins is inconvenient and unreliable. This project streamlines and improves the Java plugin development and shipment process.
The apisix-java-plugin-runner is not in its final state. The apisix-java-plugin-runner can stably run Java plugins, however, a significant work item that must still be completed is implementing Isolated Classloading. Through this project, apisix-java-plugin-runner can now run multiple plugins that were pulled from different locations. This also means that version mismatches can occur within the nested dependencies of different plugins (class shadowing), causing potential build errors. Another (optional) work item would be to expand plugin-compatability to other JVM based languages besides for Java.
Cloned Repository: https://github.com/ericluoliu/apisix-java-plugin-runner
Allows Java developers to run the apisix-java-plugin-runner process as Maven dependency rather than from source code
Relevant PR: apache/apisix-java-plugin-runner#155
Documentation: apache/apisix-java-plugin-runner#160
Maven Central JAR: https://search.maven.org/search?q=g:org.apache.apisix
Allows Java developers to:
- Easily ship their plugin to Maven as a non-executable JAR
- Use deployed plugins by injecting it as a Spring Bean
- Build/run multiple plugins
Relevant repository: https://github.com/ericluoliu/java-plugin-runner-demo
Documentation:
Speed up plugin development process
Relevant PRs:
- apache/apisix-java-plugin-runner#158
- apache/apisix-java-plugin-runner#180
- apache/apisix-java-plugin-runner#181
Documentation: apache/apisix-java-plugin-runner#166
Isolated class-loading was unable to be implemented. Three solutions were tried:
-
Implement custom class-loader and load each plugin independently
Why it failed: Spring Boot uses the LaunchedUrlClassLoader to load BOOT-INF/ classes and jars into the application. Overriding the LaunchedUrlClassLoader with my own custom classloader is unfeasible. -
Use SofaARK, a thrid party isolated classloader framework
Why it failed: Tried to incorporate SofaARK into project. Ran into errors after errors. Also, SofaARK documentation mentions that SofaARK only supports integration into simple, single-module project. Overall, SofaARK lacks documentation and is confusing to follow. -
Use SofaBOOT Module, a third party isolated module loader
Why it failed: Provided by the same organization as the one above. SofaBOOT Module was clearly in its early stages of development. Virtually no documentation available and almost no resources online referring to it.
The hardest part of this project was implementing dynamic class-loading and isolated class-loading.
I read a lot of documentation and guides for dynamic class-loading, but when I tried implementing it into the apisix-java-plugin-runner, it did not work. I used all my resources imaginable, asking my mentors, going on Google, StackOverflow, etc., but for a few days I seemed to be getting nowhere. There was very minimal information online about implementing dynamic classloading for a Spring Boot project and the guides that were available were not specific to what I wanted.
Ultimately, I just had to be creative and try stuff on my own. I had a decent idea of how Spring Boot worked, and this allowed me to hypothesize how hot reloading might look within a Spring Application.
Inside of Spring Boot applications are something called Spring Beans, and each Spring Bean represents a loaded class. So when a project boots, the Java classes are loaded. Each class is placed into a bean, and the beans are then loaded. I concluded that for dynamic classloading to work in a SpringBoot project, it was necessary to not only dynamically reload the class but also reload the bean that corresponded to the class.
After spending some time trying to implement this and patching random bugs, hot reloading of Java plugins finally worked!
Thanks to my main point of contact, ZhengSong, who frequently met with me to discuss progress, provide checkpoints, and give future guidelines. Could not have completed this project without him!
Thanks to Nicolas for giving me critical feedback and insight on various parts of my work!