Guice Framework-DI (Introduction to Dependency Injection Basics)

The so-called binding is to bind an interface to a specific class, so that the client does not need to care about the specific implementation, but only needs to obtain the corresponding interface to complete its service.

HelloWorld.java

     public interface HelloWorld {

        String sayHello();

     }

Then there is the specific implementation, HelloWorldImpl.java

     public class HelloWorldImpl implements HelloWorld {

        @Override

       public String sayHello() {

             return "Hello, world!";

         }

     }

 

Write a test example to see, HelloWorldTest.java

   public class HelleWorldTest {

        @Test

       public void testSayHello () {

         Injector inj=  Guice.createInjector(new Module() {

                @Override

                public void configure(Binder binder) {

                  binder.bind(HelloWorld.class).to(HelloWorldImpl.class);

                }

            });

           HelloWorld hw = inj.getInstance(HelloWorld.class);

           Assert.assertEquals(hw.sayHello(), "Hello, world!");

       }

   }

 

This example is very simple. The popular one is to associate an instance of HelloWorldImpl with HelloWorld. When Guice wants to obtain an instance of HelloWorld, Guice returns an instance of HelloWorldImpl, and then we can call the method of the HelloWorld service.

Self-analysis: Framework integration for Factory class!

Question (1) Is HelloWorld a singleton? Test it.

HelloWorld hw = inj.getInstance(HelloWorld.class); 

Assert.assertEquals(hw.sayHello(), "Hello, world!");

HelloWorld hw2 = inj.getInstance(HelloWorld.class);

System.out.println(hw.hashCode()+"->"+hw2.hashCode());

Assert.assertEquals(hw.hashCode(), hw2.hashCode());

Answer (1) The test result tells us that HelloWorld is not a singleton, and a new instance is returned every time.

Question (2) Is the instance of HelloWorld HelloWorldImpl? Can it be forced to change?

HelloWorld hw = inj.getInstance(HelloWorld.class);

System.out.println(hw.getClass().getName());

Answer (2),

result output

cn.imxylz.study.guice.helloworld.HelloWorldImpl, it seems that it just returns a normal instance, and does not do too much conversion and proxy.

 

Question (3), what happens if you bind multiple implementations to the same interface?

public class HelloWorldImplAgain implements HelloWorld {

    @Override

     public String sayHello() {

        return "Hello world again.";

     }

}

binder.bind(HelloWorld.class).to(HelloWorldImpl.class);

binder.bind(HelloWorld.class).to(HelloWorldImplAgain.class);

 

Answer (3), unfortunately, Guice currently doesn't seem to allow multiple instances to be bound to the same interface.

com.google.inject.CreationException: Guice creation errors:

1) A binding to cn.imxylz.study.guice.helloworld.HelloWorld was already configured at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:28). 

  at cn.imxylz.study.guice.helloworld.HelleWorldTest $ 1.configure (HelleWorldTest.java:29)

 

Question (4), can an implementation class be bound to an implementation class?

Injector inj=  Guice.createInjector(new Module() {

      @Override

       public void configure(Binder binder) {

          binder.bind(HelloWorldImpl.class).to(HelloWorldImpl.class);

       }

  });

HelloWorld hw = inj.getInstance(HelloWorldImpl.class);

System.out.println(hw.sayHello());

 

 

It is very unfortunate that you cannot bind yourself to yourself.

1) Binding points to itself. 

  at cn.imxylz.study.guice.helloworld.HelleWorldTest $ 1.configure (HelleWorldTest.java:28)

Let's take a look at the syntax of bind.

<T> AnnotatedBindingBuilder<T> bind(Class<T> type);

ScopedBindingBuilder to(Class<? extends T> implementation);

That is, only a subclass of a class can be bound to itself

. Under the transformation, use subclass instead.

    public class HelloWorldSubImpl extends HelloWorldImpl {

         @Override

         public String sayHello() {

             return "@HelloWorldSubImpl";

         }

    }

   Injector inj = Guice.createInjector(new Module() {

            @Override

           public void configure(Binder binder) {

               binder.bind(HelloWorldSubImpl.class).to(HelloWorldSubImpl.class);

           }

        });

      HelloWorldImpl hw = inj.getInstance(HelloWorldImpl.class);

      System.out.println(hw.sayHello());

Subclass binding is supported so that even if we publish an implementation class (although this is not recommended), we still have a way to replace the implementation class at a later stage.

There is an advantage to using bind. Since the generics above JAVA 5 are determined in the compiler, it can help us detect binding errors, which cannot be detected in the configuration file.

It looks like Module is like a Map, and its Value is obtained according to a Key, very simple logic.

Question (5), can it be bound to an instance constructed by ourselves?

Answer (5) Of course! See the example below.

Injector inj=  Guice.createInjector(new Module() {

             @Override

             public void configure(Binder binder) {

                binder.bind(HelloWorld.class).toInstance(new HelloWorldImpl());

             }

         });

      HelloWorld hw = inj.getInstance(HelloWorld.class);

      System.out.println(hw.sayHello());

Question (6), I don't want to provide logic to construct an object, can I?

Answer (6), Guice provides a way (Provider<T>) that allows you to provide a way to construct objects.

  Injector inj=  Guice.createInjector(new Module() {

        @Override

        public void configure(Binder binder) {

            binder.bind(HelloWorld.class).toProvider(new Provider<HelloWorld>() {

                @Override

                public HelloWorld get() {

                    return new HelloWorldImpl();

                }

            });

       }

   });

 HelloWorld hw = inj.getInstance(HelloWorld.class);

 System.out.println(hw.sayHello());

Question (7), can the implementation class be obtained without binding? For example, do I want to get an instance of HelloWorldImpl without binding it through Module?

Answer (7), yes, in fact Guice can automatically find the implementation class.

Injector inj=  Guice.createInjector();

HelloWorld hw = inj.getInstance(HelloWorldImpl.class);

System.out.println(hw.sayHello());

Question (8), can the injection be done using annotations? Don't want to manually associate implementation classes.

Answer (8), well, Guice provides an annotation method to complete the association. We need to indicate on the interface which implementation class this interface is associated with.

 @ImplementedBy(HelloWorldImpl.class)

   public interface HelloWorld {

         String sayHello();

  }

Injector inj=  Guice.createInjector();

HelloWorld hw = inj.getInstance(HelloWorld.class);

System.out.println(hw.sayHello());

 

In fact, for an interface that has been annotated, we can still use Module to associate, so the instance obtained will be the instance associated with the Module, not the instance associated with the @ImplementedBy annotation. This still follows a principle, manual is better than automatic.

Question (9) Look back at question (1) How to bind a singleton?

      Injector inj = Guice.createInjector(new Module() {

          @Override

          public void configure(Binder binder) {

           binder.bind(HelloWorld.class).to(HelloWorldImplAgain.class).in(Scopes.SINGLETON);

          }

      });

      HelloWorld hw = inj.getInstance(HelloWorld.class);

      HelloWorld hw2 = inj.getInstance(HelloWorld.class);

      System.out.println(hw.hashCode() + "->" + hw2.hashCode());

It can be seen that the instance obtained is now a singleton, and a new instance is no longer generated each time a request is made.

In fact Guice provides two Scopes,

com.google.inject.Scopes.SINGLETON和com.google.inject.Scopes.NO_SCOPE,

The so-called no scope is to generate a new instance every time.

 

For automatic injection, it is very simple, just add a Singleton annotation to the implementation class.

@Singleton

public class HelloWorldImpl implements HelloWorld {

@Override

  public String sayHello() {

    return "Hello, world!";

  }

}

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327013526&siteId=291194637