Guice--java Dependency Injection Framework

Source: Internet
Author: User

Interface-Oriented Programming

Without interface-oriented programming there is no dependency injection (Dependency injection), so revisit the interface-oriented programming before you talk about dependency injection.

PS: Relationship of Dependency Injection (di,dependency injection) and control inversion (ioc,inversion of controls)

Public interface Vehicle {public    String run ();}
public class Horse implements vehicle{    @Override public    String run () {        return "Horse run.";    }}
public class Soldier implements Hero {  Vehicle Vehicle;  Public Soldier (Vehicle Vehicle) {    this.vehicle = Vehicle;  }  @Override Public  String Fight () {    return Vehicle.run () + "charge";  }}
    1. Above is a kind of dependency injection programming, that is, the soldier fight method relies on a vehicle, we directly inject a vehicle into the soldier class, rather than temporarily create a fight within the vehicle method.
    2. Above is an interface-oriented programming approach. Assuming that vehicle is an external service that we rely on, we can implement a simple vehicle on our own, so that testing of soldier class fight methods is no longer dependent on that real external service. Of course, instead of using interface-oriented programming, you can do the same thing with a mock, but the individual feels that using a mock is obscure and error-prone.

The following is formally entered into the introduction of the use of Guice.

Put a UML diagram first to show the class structure of my demo program.

Using module binding interface and implementation, get implementation class from injector
Public interface Energy {public    String getName ();}
public class Fuel implements energy{    @Override public    String getName () {        return "Fule";    }}
@ImplementedBy (horse.class) public interface Vehicle {public    String run ();}
@Singletonpublic class Horse implements vehicle{public  static int instancenum=0;  @Inject Energy  ;  Public Horse () {    instancenum++;  }  @Override public  String run () {    return ' Horse run with ' + Energy.getname ();}  }
Public interface Hero {public    String fight ();}
public class Soldier implements Hero {  Vehicle Vehicle; Public  Soldier (Vehicle Vehicle) {    this.vehicle = Vehicle;  }  @Override Public  String Fight () {    return Vehicle.run () + "charge";  }}
 1 public class MyModule implements Module {2 @Override 3 public void Configure (Binder binder) {4 binder . Bind (Vehicle.class). Annotatedwith (Fast.class). to (Copter.class). in (Scopes.singleton); 5 Binder.bind (Vehicle.class). Annotatedwith (names.named ("Speed")). to (Airship.class);  6 binder.requeststaticinjection (Airship.class); 7 8 Binder.bind (Energy.class) to (Fuel.class); 9 Binder.bind (Energy.class). Annotatedwith (Lightenergy.class). to (Gas.class), Binder.bind (Energy.class). An Notatedwith (names.named ("Cleanenergy")). to (Solar.class); Binder.bind (Hero.class). Toprovider (HeroProvi         Der.class) Binder.bind (string.class) Annotatedwith (names.named ("Point1")). ToInstance ("0.4"); 15 InputStream stream = MyModule.class.getResourceAsStream ("App.properties"); properties appproperties = new Pro Perties (); try {appproperties.load (stream); Names.binDproperties (binder, appproperties); catch (IOException e) {binder.adderror (e); 22}23 }24}
public class Testsoldier {  @Test public  void Test () {    Injector Injector = guice.createinjector (New MyModule ( ));    Vehicle Vehicle = injector.getinstance (vehicle.class);    for (int i = 0; i < 3; i++) {      Soldier hero = new Soldier (vehicle);      Assert.assertequals ("Horse Run with Fule charge", Hero.fight ());      Assert.assertequals ("inject. Soldier ", Hero.getclass (). Getcanonicalname ());    }    Assert.asserttrue (1 = = Horse.instancenum);}  }

Put a bunch of code on it and start explaining it now.

The interface and implementation bindings are specified in module, and a module is required to be passed in when creating injector. When we want to get an instance of vehicle, we can take it directly from the injector. There is an annotation @implementedby (horse.class) on the interface vehicle, which tells Injector:vehicle that the default implementation is Horse. And horse relies on energy, what kind of energy should be used to achieve it? We note that the energy member of Horse has a @inject annotation, in which case the energy realization class is obtained from injector, and injector will ask the module, The 8th line of MyModule indicates that the default implementation class for energy is fuel.

The two methods of binding interfaces and implementations are shown here: Using @implementedby on the interface, writing Binder.bind (interface) to (Implementation) in module. The default implementation of an interface cannot have two, that is, if it appears in code:

Binder.bind (Energy.class) to (Fuel.class), Binder.bind (Energy.class). to (Gas.class);

The runtime throws an exception.

The horse class has a @singleton annotation on it, which tells Injector to create only one instance of horse, and the injector that anyone obtains from horse are the same entity, that is, their hashcode are the same. We deliberately set a static variable instancenum to record the number of times the default constructor of horse was called, and the experiment proved that the constructor was only called 1 times. @Singleton annotations This is the same way as using the in (Scopes.singleton) effect in bind, see Line 4th of MyModule.

Instances created from injector are normal instances, not proxies and conversions. If it is an agent, the canonicalname of the output instance will be: Com.sun.proxy. $Proxy 0

There are a lot of grammatical explanations in mymodule.

public class Solar implements energy {    @Override public    String getName () {        return "Solar";    }}
public class AirShip implements vehicle{  @Inject  @Named ("Cleanenergy") of  static energy;  @Override public  String run () {    return ' AirShip Fly with ' + Energy.getname ();}  }
Public class superhero implements Hero {  @Inject  @Named ("Speed")  Vehicle Vehicle;  @Override Public  String Fight () {    return Vehicle.run () + "boom";  }}
public class Testsuperhero {  @Test public  void Test () {    Injector Injector = guice.createinjector (new MyModule ());    Superhero hero = Injector.getinstance (Superhero.class);    Assert.assertequals ("AirShip Fly with Solar boom", hero.fight ());}  }

The parameters of the Injector.getinstance () method can be not only an interface, but also a concrete implementation class (no binding is required in the module at this time). When you get an instance of superhero from injector, the @inject attribute in superhero also requires that the instance be obtained from injector. So which vehicle is superhero using? Is it horse? (Because horse is the default implementation of vehicle) @named annotations are used here, referring to the 5th line of MyModule We know superhero used vehicle is actually airship. Similarly, the energy used in airship is Solar, see Line 10th of MyModule.

Note that the energy attribute of AirShip is a static variable, so Binder.requeststaticinjection (Airship.class) must be stated in MyModule; The chain of dependence from airship to energy can be passed down.

The module cannot bind itself to itself, but can be bound to subclasses.

Binder.bind (Implementation) to (Implementation) error

Binder.bind (Implementation) to (Subimplementation) correct

Public class gas implements energy {    @Override public    String getName () {        return ' gas ';    }}
public class Copter implements Vehicle {public  static int instancenum = 0;  Energy energy;  Public copter () {Energy    = new gas ();  }  @Inject  private void init (@LightEnergy energy) {    this.energy = energy;    instancenum++;  }  @Override public  String run () {    return ' copter Fly with ' + Energy.getname ();}  }
public class Weaselgirl implements Hero {  @Inject  @Fast  Vehicle Vehicle;  @Override Public  String Fight () {    return Vehicle.run () + "shoot";  }}
public class Testweaselgirl {  @Test public  void Test () {    Injector Injector = guice.createinjector (new MyModule ());    for (int i = 0; i < 3; i++) {      Weaselgirl hero = injector.getinstance (Weaselgirl.class);      Assert.assertequals ("Copter Fly with gas shoot", hero.fight ());    }    Assert.asserttrue (1 = = Copter.instancenum);}  }

Vehicle with @fast annotation in Weaselgirl, the 4th line of MyModule tells us that the vehicle implementation class should take copter at this time. Injectot takes precedence when creating an copter instance to invoke a non-private constructor of copter with @inject annotations, and if no such constructor is invoked, the empty constructor is called and injector executes all @inject methods immediately after the constructor is called. There is a @inject method called Init in Copter, the parameters in this method are @lightenergy annotated, and the 9th line of MyModule tells us that we should create a gas instance to pass to the Init () method. Since the 4th line of MyModule tells Injector:copter to be singleton, in test, although we have obtained 3 weaselgirl from Injector (each time a weaselgirl is created to request a copter), But in fact, Injetor only created a copter instance.

At this point we have learned 3 ways to bind interfaces and implementations: @ImplementedBy default bindings, binding with Annotatedwith (Annotation) when binder, and binder with Annotatedwith ( Names.named ("str")) to implement conditional binding. In fact, we can also implement a provider, when there is a dependency in a class (the dependency is an interface), by provider to provide the specific implementation class.

public class Mobile implements Vehicle  ;  Public Mobile () {Energy    = new gas ();  }  @Inject public  Mobile [energy] {    this.energy = energy;  }  @Override public  String run () {    return ' Mobile run with ' + Energy.getname ();}  }
public class Vehicleprovider implements provider<vehicle> {  double point1;  Double Point2;  @Inject public  Vehicleprovider (@Named ("Point1") string P1, @Named ("Point2") string p2) {    this.point1 = Double.parsedouble (p1);    This.point2 = double.parsedouble (p2);  }  @Override public  Vehicle get () {    Injector Injector = guice.createinjector (New MyModule ());    Double rnd = Math.random ();    if (Rnd < point1) {      return injector.getinstance (Mobile.class);    } else if (Rnd < Point2) {      return Inje Ctor.getinstance (Airship.class);    } else {      return injector.getinstance (Mobile.class);}}}  
public class Frogman implements Hero {  Vehicle Vehicle;  Public frogman (provider<vehicle> Provider) {    this.vehicle = Provider.get ();  }  @Override Public  String Fight () {    return Vehicle.run () + "hack";  }}
public class Testfrogman {  @Test public  void Test () {    Injector Injector = guice.createinjector (New MyModule ());    provider<vehicle> Provider = injector.getinstance (vehicleprovider.class);    for (int i = 0; i < i++) {      frogman hero = new Frogman (provider);      System.out.println (Hero.fight ());    }    System.out.println (Copter.instancenum);  }}

A provider is required in the Frogman constructor, and we pass in a vehicleprovider. The Vehicleprovider get method randomly returns the mobile and airship two entities, where the stochastic algorithm relies on two parameters point1 and Point2. Because Vehicleprovider is obtained from injector, injector calls Vehicleprovider's @inject constructor when it creates the Vehicleprovider instance. The parameters used in @Inject constructors are all provided by injector. The 14th line of MyModule tells us that point1 equals 0.4, which is an example of binding constants to PrimitiveType. In fact, you can also use the external configuration file to bind the constant to a string variable, such as MyModule Line 15th to line 22nd is read from a peoperties file configuration to bind the constant value to the string variable, our Point2 is in this way to assign value.

public class Heroprovider implements provider
public class Testheroprovider {  @Test public  void Test () {    Injector Injector = guice.createinjector (new MyModule ());    for (int i = 0; i < i++) {      Hero Hero = injector.getinstance (hero.class);      System.out.println (Hero.fight ());    }    System.out.println (Copter.instancenum);  }}

The 12th line of MyModule indicates which specific hero the Heroprovider decides to produce when requesting hero from injector.

Download all the code for this article

Dependencies are introduced in the MAVEN project:

<dependency>

<groupId>com.google.inject</groupId>

<artifactId>guice</artifactId>

<version>3.0</version>

</dependency>

    • This article is from: Linux Learning Tutorial Network

Guice--java Dependency Injection Framework

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.