4

I'm working on a Spring Boot application. I want to provide a (pretty rudimentary) plugin system. Initially I was hoping it'd be enough to just add the JAR to the classpath like so:

URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;

Method method = sysclass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(sysloader, new File("./plugin/plugin.jar").toURI().toURL());

SpringApplication.run(Application.class, args);

In the plugin.jar is a class annotated with @Controller and a RequestMapping. The context loads fine and the constructor of the controller is getting called as well. However, looking at the logs, I can see that the RequestMapping did not get picked up.

Additionally, if I try to @Autowire a JpaRepository in the plugin controller it fails complaining that it can't find the repository interface class (which I'm guessing is some problem that arose from me messing around with the ClassLoader).

Just autowiring the repository in my main application works fine though, so it shouldn't be an issue with its configuration.

Is there something I'm doing wrong? Can I maybe configure Springs ApplicationContext or its ClassLoader to make this work correctly?

To summarise, I want to load some Controllers (and maybe other Spring components) at runtime from an external JAR in another folder.

mhlz
  • 3,497
  • 2
  • 23
  • 35
  • Hopefully I understand you correctly. In your Spring configuration you can do where the package exists in your external jar. This will scan the package for annotations and create the Controller and its RequestMappings in your Spring container, so that you can autowire them. – ConMan Jun 11 '15 at 14:17
  • I should've clarified that I want to avoid using XML configuration if possible. Right now I'm using `@ComponentScan("com.base.package")` to tell Spring to load everything under it. This only works for compile time dependencies though and not for JARs that are supposed to be loaded at runtime. My goal is to have all those plugins in the plugin folder be loaded when the application starts, ideally not knowing anything about them during compilation. – mhlz Jun 11 '15 at 14:22
  • Perhaps you should have a look at https://github.com/spring-projects/spring-plugin . I do not think, that this behavior is supported out of the box with spring boot. – Philipp Hügelmeyer Jun 11 '15 at 15:13
  • Spring Plugin does not seem like it provides exactly what we want. However, we might be able to work with it. Thank you! – mhlz Jun 13 '15 at 12:59

2 Answers2

0

For now I just ended up declaring profiles in my application pom for my various plugins and I just compile it using the profiles of the plugins that I want. It's not very dynamic but at least I can separate the plugin development from the application development completely and have Spring pick up on all of the plugin's components.

This is not exactly what I wanted, but I figured I'd describe how I "solved" it anyway. If anyone knows a way to make this work with external JARs I'd be happy to accept that answer instead!

mhlz
  • 3,497
  • 2
  • 23
  • 35
0

I solved this by importing the dependency in which my controller resides, and then calling the packages of the controller and the main run method the same name (but in different projects). It's a hack, but it works.

Freddie
  • 13
  • 3
  • That is exactly the same thing I described in my own answer. Additionally you don't need to actually name the packages the same name. They just need a common root and you can use annotations to tell SpringBoot where to scan: http://stackoverflow.com/questions/29257409/maven-configuration-with-spring-boot-multi-modules-run-application-in-intell/29258163#29258163 – mhlz Sep 17 '15 at 08:22