4

Is there an easy way to enumerate all the singleton instances already created by a Guice Injector? Or alternately a way to get all singletons that implement a specific interface?

I would like to find all singleton instances that implement java.io.Closeable so I can close them cleanly when my service is shut down.

David Tinker
  • 9,383
  • 9
  • 66
  • 98
  • I would prefer not to have to create a 'wrapper' object referencing all of them or to have them register themselves with an injected 'closer' singleton if possible. Guice must have references to all of the singleton's somewhere ... – David Tinker Dec 25 '12 at 18:44

1 Answers1

8

This would be fairly easy to write using Guice's SPI. Guice's Injector instance exposes a getAllBindings() method that lets you iterate through all of the bindings.

// Untested code. May need massaging.
private void closeAll(Injector injector) {
  for(Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
    final Binding<?> binding = entry.getValue();
    if (Closeable.class.isAssignableFrom(
        entry.getKey().getTypeLiteral().getRawType())) {
      binding.accept(new DefaultBindingScopingVisitor<Void>() {
        @Override public Void visitEagerSingleton() {
          Closeable instance = (Closeable) (binding.getProvider().get());
          try {
            instance.close();
          } catch (IOException e) {
            // log this?
          }
          return null;
        }
      });
    }
  }
}

Note that I only overrode visitEagerSingleton and that you may have to modify the above to handle lazily-instantiated @Singleton instances with implicit bindings. Also note that if you bind(SomeInterface.class).to(SomeClosable.class).in(Singleton.class) you may need to make the SomeInterface.class Closable, though you could also instantiate every Singleton (by putting the Closable check inside the scope visitor) to determine if the provided instance itself is Closable regardless of the key. You may also be able to use Reflection on the Binding's Key to check whether the type is assignable to Closable.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Hmm. That only seems to find explicitly bound singletons, not ones just annotated with @Singleton with no binding defined in the module? – David Tinker Dec 26 '12 at 07:36
  • Right, but since getAllBindings includes lazy bindings, you can just implement your visitor's `visitScopeAnnotation`, which I omitted for brevity. You may want to bind your Singletons explicitly anyway, though--if they have long startup times you may benefit from Guice's eager instantiation to make your application's performance more predictable and reduce the chance of unsatisfied dependency errors long after startup. – Jeff Bowman Dec 26 '12 at 16:04
  • In the end I just did entry.value.provider.get() to get each instance and test for Closable. Tx. – David Tinker Dec 30 '12 at 12:27
  • This works well for eager, but for lazy singletons - I think the author intended to go over already instantiated instances only, and not to instantiate singleton just for calling its close() method. Calling binding.getProvider() get() will create a new instance if was never created yet – Denis Itskovich Feb 04 '20 at 04:16