I want to build a server system consiting of several plugins.
Hence I want to build a core plugin which is used by all other and provides classes to the others (e.g. UserSystem with SQL integration). Since Sponge uses dependencie injection quite often I asked myself if I could extend this feature to provide my own instances via @Inject for other plugins.
You can create your own guice injector module. Read up on guice here:
I’m not sure how well this will work cross plugin.
Wouldn’t the other plugins need to be constructed by your injector instead of Sponges, or otherwise get a reference to your injector somehow and construct it’s classes using your injector?
Sounds a round about way of doing things but maybe I’m not familiar enough on Guice on how to make that clean.
I would be tempted to recommend just using factories to provide the dependencies and let the other plugins use their own Guice modules in order to set that as a provider for the given interfaces they want.
I know i can create my own Injector but like ryantheleach mentioned the plugins would have to be instanciated by my Injector to work properly and this would break Sponge’s dependency injection.
But if we had access to Sponge’s Injector we could create a child injector and replace Sponge’s original injector by the newly created one.
That seems like a bad idea. The whole goal of APIs like sponge is to be something developers can build against, rely on and also, to make multiple mods / plugins / whatever work side by side. What if two plugins want to replace the Injector? Which Injektor will Sponge use in the end?
Not to mention you’d need to ship your own modified implementation.
Actually, sponge already has multiple injectors. A global one for things like game, root configuration directory, etc. and one child injector for each plugin, containing plugin config and the like. So, modifying the child injector would have no impact on other plugins.
Due to the way guice works, we can actually inject the injector used to create an instance. So, the following code would work:
@Plugin(…)
public class MyPlugin {
@Inject
private Injector pluginInjector;
@Subscribe
public void init(InitializationEvent evt) {
Injector myInjector = pluginInjector.createChild(new MyModule());
myService = myInjector.getInstance(MyService.class);
}
}
Of course, it would be a lot easier if we could specify MyModule to be included into the plugin injector, this would clean up the code by a lot.
Another solution would by to use guice’s implicit bindings, but that will only work for basic tasks. I’m also not 100% sure which injector would end up creating the implicit binding in the end.
@xfel The whole point was to be able to inject cross-plugin which you can’t easily do.
Oh sorry, it seems that I missed that part. But I just checked, it seems that JIT bindings are not disabled in the parent injector. So if I have an API interface and an implementation for it, you could use @ImplementedBy to force a JIT binding. If you implementation is annotated with @Singleton, everyone will get the same instance, even if they are in different plugins. The downside of this is that your API class needs a reference to your implementation class.