Hierarchical injectors (or alternatives?)

283 views
Skip to first unread message

Benjamin Muskalla

unread,
Jul 8, 2013, 6:25:40 AM7/8/13
to google...@googlegroups.com
Hey,

I'm just trying to get my head around the following problem. I'm working on a framework which exposes SPI to other developers.
The current structure (and it's injector structure) is like the following:

* Root (root injector)
** services (child injector)
*** operations (child child injector)

Each level only knows about the class objects for the level below (eg. a service only knows about which classes implement it's operations).
The initial thought was to pass injectors down the chain to instantiate and inject dependencies for these classes (eg. @Inject Injector) and then creating the child injectors.
While this works fine, I just stumbled on one problem which revealed that the whole hierarchy might not be as easy as I thought.
Let's say the root injector provides A, a Service depends on nothing but provides B and one of its operations depends on A and B.
When passing down the Injector to the operation, the operation only sees A but not B as the service doesn't depend on anything and thus the root injector get's used and injected.
Adding @Inject A to the service resolves the problem but that's actually a little but too much trickery and forces service implementations to always know what parent dependencies they'd need to depend on in order to get the right injector.

While this behaviour is intentional as far as I read the Guice docs, I wondered what alternatives would make sense to build up the hierarchy of dependencies in order to create the operations.

Thanks,
  Benjamin

Thomas Matthijs

unread,
Jul 8, 2013, 9:42:15 AM7/8/13
to google...@googlegroups.com
One way to solve this (if i understand the problem correctly) is to always require explicit bindings  http://google-guice.googlecode.com/git/javadoc/com/google/inject/Binder.html#requireExplicitBindings()

Tim Boudreau

unread,
Jul 10, 2013, 3:28:11 AM7/10/13
to google...@googlegroups.com
I may be misunderstanding something, but what you're talking about sounds a lot like the classloader-partitioning that OSGi or the NetBeans module system do.

I think hierarchical injectors may actually be unnecessary.  If you use a runtime such as NetBeans' one (does not have to be a GUI app) or an OSGi container, that takes care of the class visibility issues.

Then you don't actually need hierarchical injectors at all - a "child" module can't ask for a type to be injected which it can't refer to at runtime at all.  Run your bootstrapping code in the parent classloader and use some sort of service lookup pattern to bootstrap all the Guice modules registered - something like

        ClassLoader ldr = ...get classloader which can see everything...
        Injector inj = Guice.createInjector(ServiceLoader.load(Module.class, ldr));

(this uses JDK 6's ServiceLoader, which works over flat files in META-INF/services - NetBeans lookup library contains an annotation + processor which will generate them).  I'm probably risking starting a religious war by suggesting using ServiceLoader here - but if you want to build a self-bootstrapping system that doesn't necessarily know all of it's components at compile-time, you need something like that (and bootstrapping is a very different problem than injection).

Of course, if two pieces of the system might both want to bind the same type, then you may want to start fiddling with private binders (see Binder.newPrivateBinder()) and so forth.

But it sounds like the problem you want to solve is isolating components from each other in terms of their runtime classpath.  That's a job for classloaders, and is a well solved problem in many Java module systems - and gives you a stronger guarantee that components can't see - can't even load - classes they shouldn't be concerned with, than anything you could do with Guice. 

-Tim

Reply all
Reply to author
Forward
0 new messages