Quick background: I am working on developing an interface that will be implemented by myself and other developers. This interface will allow users to "plugin" new functional code into a system for new use. This new code will be called from an already running server/application. (TLDR: I need to develop the ability for plugins to be installed into my application on the fly)
All the work I have done with interfaces so far have been for internal coding purposes, not to be exposed outward. The only way I can think of to allow users to plugin new code implementing interfaces, would be for the user to somehow hook a JAR file in containing the implementing class and somehow defining its class signature for call. This seems like something that has been done before, I just have never been exposed into the coding side of it.
Is there a framework I could use to allow this plugin of new Java code during server/application runtime? I have used APIs before, but in more of the web service exposing sense where you are consuming a service and not "implementing" some core interface.
For reference I am using a Java backend, with Spring for the main application.
-
2Looks like a duplicate of stackoverflow.com/questions/25449/…Esben Skov Pedersen– Esben Skov Pedersen2016年03月28日 13:50:54 +00:00Commented Mar 28, 2016 at 13:50
-
1@EsbenSkovPedersen that led me into a rabbit hole which eventually gave me everything I needed and then some. Thank you very much. (-admins: Duplicate, close is fine by me)Walls– Walls2016年03月28日 22:07:59 +00:00Commented Mar 28, 2016 at 22:07
-
@Walls duplicates must be on the same site. Just because SO has a similar question does not mean this one is a duplicate of it. You could summarize what you found in an answer to this question and link to the SO question, since answers are a bit more permanent than comments.user22815– user228152016年03月30日 05:13:19 +00:00Commented Mar 30, 2016 at 5:13
2 Answers 2
After looking into a related post on Stack Overflow, I found there to be a variety of different tools at my disposal to do "plugin" style development.
First, I was close with "API" but the correct solution is an "SPI" or Service Provider Interface. I found a very good post describing the difference on Stack Overflow. To summarize: API is a set of classes/interfaces/methods that you CALL and USE to achieve a goal. Compared to a SPI which is a set of classes/interfaces/methods that you EXTEND and IMPLEMENT to achieve a goal.
There are many ways I am still looking through to find the right solution for me, but it seems that using Java's ClassLoader
or URLClassLoader
will be the way to go. Oracle provides a great tutorial on how to implement this here.
There are many tools out there that can provide support for this such as Apache Aries and OSGi.
Have a look at FlexiCore, an open-source framework that brings modularity to spring boot utilizing plugins(jars) loaded at runtime See wizzdi and FlexiCore. for example FlexiCore allows you to create a project ( compiled into a seperate jar from your main application) that contains a spring bean as follows:
@Component
@Extension
public class HelloWorldService implements ServicePlugin{
public String hello() {
return "Hello World!";
}
}
it will be automatically be loaded once placed inside the designated plugins folder, it basically allows a full support for most(all) of spring boot features , so for example you can add a RestController bean to your jar as well , FlexiCore will automatically load that bean allowing you to call the controller as if it was in your main application jar:
@RestController
@Extension
public class TestEntityController implements Plugin {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@Autowired
private TestEntityService testEntityService;
@PostMapping("/createTestEntity")
public TestEntity createTestEntity(@RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
return testEntityService.createTestEntity(name);
}
@GetMapping("{id}")
public TestEntity getTestEntity(@PathVariable("id")String id) {
return testEntityService.getTestEntity(id);
}
}
Disclaimer: I am the CTO of wizzdi, the company powering FlexiCore.