Vejledning til Google Guice

1. Introduktion

Denne artikel vil undersøge det grundlæggende i Google Guice. Vi ser på tilgange til at udføre grundlæggende DI-opgaver (Dependency Injection) i Guice.

Vi sammenligner og kontrasterer Guice-tilgangen med mere etablerede DI-rammer som Spring and Contexts and Dependency Injection (CDI).

Denne artikel forudsætter, at læseren har en forståelse af det grundlæggende i afhængighedsinjektionsmønsteret.

2. Opsætning

For at bruge Google Guice i dit Maven-projekt skal du tilføje følgende afhængighed til din pom.xml:

 com.google.inject guice 4.1.0 

Der er også en samling Guice-udvidelser (vi vil dække dem lidt senere) her samt tredjepartsmoduler for at udvide Guices muligheder (hovedsageligt ved at tilbyde integration til mere etablerede Java-rammer).

3. Grundlæggende afhængighedsinjektion med guice

3.1. Vores prøveansøgning

Vi arbejder med et scenarie, hvor vi designer klasser, der understøtter tre kommunikationsmidler i en helpdesk-virksomhed: E-mail, SMS og IM.

Overvej klassen:

offentlig klassekommunikation {@Inject private Logger logger; @Inject private Communicator communicator; offentlig kommunikation (boolsk keepRecords) {hvis (keepRecords) {System.out.println ("Beskedlogning aktiveret"); }} offentlig boolsk sendMessage (streng besked) {return communicator.sendMessage (besked); }}

Det her Meddelelse klasse er den grundlæggende enhed for kommunikation. En forekomst af denne klasse bruges til at sende meddelelser via de tilgængelige kommunikationskanaler. Som vist ovenfor, Meddelelse har en Kommunikator som vi bruger til at udføre den aktuelle meddelelsestransmission.

Det grundlæggende indgangspunkt i Guice er Injektor:

public static void main (String [] args) {Injector injector = Guice.createInjector (new BasicModule ()); Kommunikationskommissioner = injektor.getInstance (Kommunikation.klasse); } 

Denne hovedmetode henter en forekomst af vores Meddelelse klasse. Det introducerer også et grundlæggende koncept med Guice: Modul (ved brug af BasicModule i dette eksempel). Det Modul er den grundlæggende enhed for definition af bindinger (eller ledninger, som det er kendt om foråret).

Guice har vedtaget en kode-første tilgang til afhængighedsindsprøjtning og -styring så du vil ikke beskæftige dig med en masse XML out-of-the-box.

I eksemplet ovenfor er afhængighedstræet for Meddelelse vil blive implicit injiceret ved hjælp af en funktion kaldet just-in-time binding, forudsat at klasser har standard no-arg konstruktør. Dette har været en funktion i Guice siden starten og kun tilgængelig i foråret siden v4.3.

3.2. Guice Bindinger

Binding er at Guice som ledninger er til foråret. Med bindinger, dig definere, hvordan Guice vil injicere afhængigheder ind i en klasse.

En binding defineres i en implementering af com.google.inject.AbstractModule:

offentlig klasse BasicModule udvider AbstractModule {@ Override-beskyttet ugyldig konfiguration () {bind (Communicator.class). til (DefaultCommunicatorImpl.class); }}

Dette modul implementering specificerer, at en forekomst af StandardCommunicatorImpl skal injiceres overalt, hvor en Kommunikator variabel findes.

En anden inkarnation af denne mekanisme er navngivet binding. Overvej følgende variabeldeklaration:

@Inject @Named ("DefaultCommunicator") Communicator communicator; 

Til dette vil vi have følgende bindende definition:

@ Override beskyttet ugyldig konfiguration () {bind (Communicator.class) .annotatedWith (Names.named ("DefaultCommunicator")) .to (Communicator.class); } 

Denne binding vil give en forekomst af Kommunikator til en variabel, der er kommenteret med @Named (“Standardkommunikator”) kommentar.

Du vil bemærke @Indsprøjte og @Som hedder kommentarer ser ud til at være lånebeskrivelser fra Jakarta EEs CDI, og det er de også. De er i com.google.inject. * pakke - du skal være forsigtig med at importere fra den rigtige pakke, når du bruger en IDE.

Tip: Mens vi lige sagde at bruge Guice-leveret @Indsprøjte og @Som hedder, er det værd at bemærke, at Guice yder support til javax.inject.Inject og javax.inject.Named, blandt andre Jakarta EE-kommentarer.

Du kan også indsprøjte en afhængighed, der ikke har en standard no-arg-konstruktør ved hjælp af konstruktørbinding:

offentlig klasse BasicModule udvider AbstractModule {@Override beskyttet ugyldig konfigurere () {bind (Boolean.class) .toInstance (true); bind (Communication.class) .toConstructor (Communication.class.getConstructor (Boolean.TYPE)); } 

Uddraget ovenfor indsprøjter en forekomst af Meddelelse ved hjælp af konstruktøren, der tager en boolsk argument. Vi leverer rigtigt argument til konstruktøren af definerer en ikke-målrettet binding af Boolsk klasse.

Det her ikke-målrettet binding vil ivrigt blive leveret til enhver konstruktør i bindingen, der accepterer a boolsk parameter. Med denne tilgang er alle afhængigheder af Meddelelse injiceres.

En anden tilgang til konstruktorspecifik binding er instansbinding, hvor vi leverer en instans direkte i bindingen:

offentlig klasse BasicModule udvider AbstractModule {@ Override beskyttet ugyldig konfigurere () {bind (Communication.class) .toInstance (ny kommunikation (sand)); }}

Denne binding vil give en forekomst af Meddelelse klasse uanset hvor en Meddelelse variabel erklæres.

I dette tilfælde kobles imidlertid ikke klassens afhængighedstræ automatisk. Du bør begrænse brugen af ​​denne tilstand, hvor der ikke er nogen tung initialisering eller afhængighedsinjektion nødvendig.

4. Typer af afhængighedsinjektion

Guice understøtter de standardtyper af injektioner, som du ville have forventet med DI-mønsteret. I Kommunikator klasse, skal vi indsprøjte forskellige typer CommunicationMode.

4.1. Feltinjektion

@Inject @Named ("SMSComms") KommunikationsMode smsComms;

Brug det valgfri @Som hedder kommentar som en kvalifikator til at implementere målrettet injektion baseret på navnet

4.2. Metodeinjektion

Her bruger vi en setter-metode til at opnå injektionen:

@Inject public void setEmailCommunicator (@Named ("EmailComms") CommunicationMode emailComms) {this.emailComms = emailComms; } 

4.3. Konstruktørinjektion

Du kan også injicere afhængigheder ved hjælp af en konstruktør:

@Injicer offentlig kommunikation (@Named ("IMComms") CommunicationMode imComms) {this.imComms = imComms; } 

4.4. Implicitte injektioner

Guice vil implicit injicere nogle komponenter til generelle formål som f.eks Injektor og en forekomst af java.util.Logger, blandt andre. Du vil bemærke, at vi bruger loggere gennem prøverne, men du finder ikke en egentlig binding til dem.

5. Scoping in Guice

Guice understøtter de anvendelsesområder og afgrænsningsmekanismer, vi er vant til i andre DI-rammer. Guice leverer som standard en ny forekomst af en defineret afhængighed.

5.1. Singleton

Lad os injicere en singleton i vores ansøgning:

bind (Communicator.class) .annotatedWith (Names.named ("AnotherCommunicator")) .to (Communicator.class) .in (Scopes.SINGLETON); 

Det i (Scopes.SINGLETON) angiver, at nogen Kommunikator felt med @Named (“AnotherCommunicator”) får en singleton injiceret. Denne singleton er dovent startet som standard.

5.2. Ivrig Singleton

Lad os nu injicere en ivrig singleton:

bind (Communicator.class) .annotatedWith (Names.named ("AnotherCommunicator")) .to (Communicator.class) .asEagerSingleton (); 

Det asEagerSingleton () kald definerer singleton som ivrigt instantieret.

Ud over disse to anvendelsesområder understøtter Guice brugerdefinerede anvendelsesområder såvel som kun internet @RequestScoped og @SessionScoped kommentarer, leveret af Jakarta EE (der er ingen versioner, der leveres af Guice, af disse kommentarer).

6. Aspektorienteret programmering i Guice

Guice er i overensstemmelse med AOPAlliance's specifikationer for aspektorienteret programmering. Vi kan implementere den afgørende logningsaflytter, som vi vil bruge til at spore afsendelse af meddelelser i vores eksempel i kun fire trin.

Trin 1 - Implementér AOPAlliance's Metode Interceptor:

offentlig klasse MessageLogger implementerer MethodInterceptor {@Inject Logger logger; @Override public Object invoke (MethodInvocation invocation) throw Throwable {Object [] objectArray = invocation.getArguments (); for (Objektobjekt: objectArray) {logger.info ("Afsender besked:" + objekt.tilString ()); } returnere indkaldelse. fortsæt (); }} 

Trin 2 - Definer en almindelig Java-kommentar:

@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.METHOD) offentlig @interface MessageSentLoggable {} 

Trin 3 - Definer en binding til en matcher:

Matcher er en Guice-klasse, som vi bruger, specificerer de komponenter, som vores AOP-kommentar gælder for. I dette tilfælde ønsker vi, at kommentaren gælder for implementeringer af CommunicationMode:

offentlig klasse AOPModule udvider AbstractModule {@Override beskyttet ugyldig konfigurere () {bindInterceptor (Matchers.any (), Matchers.annotatedWith (MessageSentLoggable.class), ny MessageLogger ()); }} 

Vi har specificeret en Matcher her, der vil anvende vores MessageLogger aflytter til nogen klasse, der har MessageSentLoggable annotering anvendt på dens metoder.

Trin 4 - Anvend vores kommentar til vores kommunikationsmetode og indlæs vores modul

@Override @MessageSentLoggable offentlig boolsk sendMessage (streng besked) {logger.info ("SMS-besked sendt"); returner sandt; } offentlig statisk ugyldig hoved (String [] args) {Injektorinjektor = Guice.createInjector (ny BasicModule (), ny AOPModule ()); Kommunikationskommissioner = injektor.getInstance (Kommunikation.klasse); }

7. Konklusion

Efter at have set på grundlæggende Guice-funktionalitet kan vi se, hvor inspirationen til Guice kom fra foråret.

Sammen med sin støtte til JSR-330 sigter Guice mod at være en injektionsfokuseret DI-ramme (mens Spring giver et helt økosystem til programmeringskomfort ikke nødvendigvis kun DI), der er målrettet mod udviklere, der ønsker DI-fleksibilitet.

Guice er også meget udvidelig, så programmerere kan skrive bærbare plugins, der resulterer i fleksible og kreative anvendelser af rammen. Dette er i tillæg til den omfattende integration, som Guice allerede leverer til mest populære rammer og platforme som Servlets, JSF, JPA og OSGi, for at nævne nogle få.

Du kan finde al kildekoden, der bruges i denne vejledning, i vores GitHub-projekt.