简体   繁体   中英

Create multiple instances of the same class with Guice

Sorry if it's a trivial question, I am new to Guice. Let's say I have the following class:

public class MyClass {
     @Inject
     public MyClass(final MyDependency myDependency) {
          this.name = myDependency.getName();
     }

     public String getName() {
          this.name;
     }
}

Then somewhere else I want to do:

public class SomeOtherClass {
    public void test() {
        MyClass instanceFoo = injector.getInstance(MyClass.class);
        MyClass instanceBar = injector.getInstance(MyClass.class);

        assertTrue("foo", instanceFoo.getName());
        assertTrue("bar", instanceBar.getName());
    }
}

I would like to have two instances of "MyClass", one which has a name of "foo" and one with a name of "bar" (ie each of them has a different instance of it's dependency as well). How can I add those 2 instances to my injector, and how can I retrieve each of them with "injector.getInstance"?

I don't want to create a subclass of "MyClass" for each possible dependency.

Thanks!

Your question, as in the title, has a simpler solution: If you want an arbitrary number of instances of MyClass or MyDependency, you can inject a Provider<MyClass> or Provider<MyDependency> . This is true whether or not you've actually bound a Provider in a Module; for any T available in the graph Guice can actually inject either T or Provider<T> . (These correspond to Injector.getInstance and Injector.getProvider respectively.)

As in the body of the question, there are two pieces: Making more than one injectable Key for the same Class , and setting up the instances the way you want with different names and injected dependencies.

Keys and Binding Annotations

Guice identifies bindings using a Key , which is a fully-qualified class (like MyClass or List<MyClass> ) combined with an optional "binding annotation". This is an annotation that is itself annotated with BindingAnnotation or javax.inject.Qualifier ; you can create your own, or use the built in one called @Named that takes a String (so @Named("foo") is different from @Named("bar") ).

Most of the time, you can get by without using Key directly: Use annotatedWith in your bind calls or add the annotation onto @Provides methods, and request them by putting the annotation onto constructor parameters or @Inject-annotated fields. However, you can still use getInstance and getProvider by creating a Key manually, using the static methods on Key. (For complicated cases, use TypeLiteral or Names.named ; see their docs for details.)

Setting up instances

Now that you know how to inject @Named("foo") MyClass or @Foo MyClass , how do you provide them? Depending on your needs, I'd choose one of three options: binding toInstance , using a @Provides method, or creating an "assisted injection" factory.

  • If your MyClass instances don't need injection themselves, and you don't mutate or manipulate instance state, you could just prepare the instances named as needed and then bind them with toInstance .

  • You could also write a @Provides @Named("foo") MyClass method that takes a MyClass parameter (which Guice supplies through the injector), sets the name, and returns the instance. This is a low-overhead alternative to writing a Provider class or instance, and will get you a fresh instance rather than the sharing that a toInstance binding would imply.

  • If you really want the name to be a part of your class's constructor parameters, perhaps to keep the instance immutable, you can use "Assisted Injection" to tell Guice which parameters you supply yourself and which come from the Guice injector. This would allow you to inject a MyClass.Factory and call myClassFactory.create("foo") , which you could do directly in your consuming classes, or using the @Provides technique above. The details are a little beyond the scope of the question, but look up "Assisted Injection" for details on syntax and on adding the appropriate JAR.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM