Guice vs Spring - injekcia závislostí

1. Úvod

Google Guice a Jar sú dva robustné rámce používané na vkladanie závislostí. Oba rámce pokrývajú všetky pojmy vkladania závislostí, ale každý z nich má svoj vlastný spôsob implementácie.

V tomto výučbe si ukážeme, ako sa rámce Guice a Spring líšia v konfigurácii a implementácii.

2. Maven závislosti

Začnime tým, že do našich pridáme závislosti Guice a Spring Maven pom.xml spis:

 org.springframework jarný kontext 5.1.4.RELEASE com.google.inject guice 4.2.2 

Vždy máme prístup k najnovším jarný kontext alebo guice závislosti od Maven Central.

3. Konfigurácia injektáže závislosti

Závislosť injekcie je programovacia technika, ktorú používame na to, aby naše triedy boli nezávislé od ich závislostí.

V tejto časti sa zmienime o niekoľkých základných funkciách, ktoré sa medzi Spring a Guice líšia v spôsoboch konfigurácie vkladania závislostí.

3.1. Jarné vedenie

Jar deklaruje konfigurácie vstrekovania závislostí v špeciálnej konfiguračnej triede. Túto triedu musí komentovať @ Konfigurácia anotácia. Jarný kontajner používa túto triedu ako zdroj definícií fazule.

Triedy riadené Jarom sa nazývajúJarná fazuľa.

Jar využíva @Autowired anotácia na automatické prepojenie závislostí. @Autowired je súčasťou základných anotácií Spring. Môžeme použiť @Autowired na členských premenných, metódach nastavovača a konštruktoroch.

Jar tiež podporuje @Inject. @Inject je súčasťou Java CDI (Contexts and Dependency Injection), ktorá definuje štandard pre vkladanie závislostí.

Povedzme, že chceme automaticky prepojiť závislosť s členskou premennou. Môžeme to jednoducho anotovať @Autowired:

@ Komponenta verejná trieda UserService {@Autowired private AccountService accountService; }
@Component public class AccountServiceImpl implementuje AccountService {}

Po druhé, poďme vytvoriť konfiguračnú triedu, ktorá sa použije ako zdroj fazule pri načítaní nášho kontextu aplikácie:

@Configuration @ComponentScan ("com.baeldung.di.spring") verejná trieda SpringMainConfig {}

Upozorňujeme, že sme tiež pridali anotácie UserService a AccountServiceImpl s @ Komponent zaregistrovať ich ako fazuľa. Je to @ComponentScan anotácia, ktorá povie Springu, kde má hľadať pre anotované komponenty.

Aj keď sme anotovali AccountServiceImpl,Jar to môže mapovať na AccountService keďže sa realizuje AccountService.

Potom musíme definovať kontext aplikácie pre prístup k fazuľkám. Upozorňujeme, že na tento kontext sa budeme odvolávať vo všetkých našich jarných testoch jednotiek:

ApplicationContext context = nový AnnotationConfigApplicationContext (SpringMainConfig.class);

Teraz za behu môžeme získať AccountService príklad z našej UserService fazuľa:

UserService userService = context.getBean (UserService.class); assertNotNull (userService.getAccountService ());

3.2. Guice Binding

Guice spravuje svoje závislosti v špeciálnej triede nazývanej modul. Modul Guice musí rozširovať Abstraktný modul triedy a prepísať jeho Konfigurovať () metóda.

Guice používa väzbu ako ekvivalent elektroinštalácie na jar. Jednoducho povedané, väzby nám umožňujú definovať, ako budú do triedy vložené závislosti. Väzby Guice sú deklarované v našom module Konfigurovať () metóda.

Namiesto @Autowired, Guice používa @Inject anotácia na vloženie závislostí.

Vytvorme ekvivalentný príklad Guice:

verejná trieda GuiceUserService {@Inject private AccountService accountService; }

Po druhé, vytvoríme triedu modulu, ktorá je zdrojom našich definícií väzieb:

public class GuiceModule extends AbstractModule {@Override protected void configure () {bind (AccountService.class) .to (AccountServiceImpl.class); }}

Za normálnych okolností očakávame, že Guice vytvorí inštanciu každého objektu závislosti od svojich predvolených konštruktorov, ak v Konfigurovať () metóda. Ale keďže rozhrania nemožno vytvoriť priamo z inštancie, musíme definovať väzby povedať Guice, ktoré rozhranie bude spárované s akou implementáciou.

Potom musíme definovať Injektor použitím GuiceModule získať inštancie našich tried. Len poznamenajme, že to využijú všetky naše testy Guice Injektor:

Injector injector = Guice.createInjector (nový GuiceModule ());

Nakoniec za behu načítame a GuiceUserService napríklad s nenulovou hodnotou accountService závislosť:

GuiceUserService guiceUserService = injector.getInstance (GuiceUserService.class); assertNotNull (guiceUserService.getAccountService ());

3.3. Anotácia Spring @Bean

Jar tiež poskytuje anotáciu na úrovni metódy @Bean zaregistrovať fazuľu ako alternatívu k anotáciám na úrovni triedy ako @ Komponent. Návratová hodnota a @Bean komentovaná metóda je v kontajneri zaregistrovaná ako fazuľa.

Povedzme, že máme príklad BookServiceImpl ktoré chceme sprístupniť na injekciu. Mohli by sme použiť @Bean zaregistrovať našu inštanciu:

@Bean public BookService bookServiceGenerator () {return new BookServiceImpl (); }

A teraz môžeme získať BookService fazuľa:

BookService bookService = context.getBean (BookService.class); assertNotNull (bookService);

3.4. Anotácia spoločnosti Guice @Provides

Ako ekvivalent k jari @Bean anotácia, Guice má zabudovanú anotáciu @ Poskytuje robiť tú istú prácu. Páči sa mi to @Bean, @ Poskytuje sa uplatňuje iba na metódy.

Teraz poďme implementovať predchádzajúci príklad Spring bean s Guice. Všetko, čo musíme urobiť, je pridať do našej triedy modulov nasledujúci kód:

@Provides public BookService bookServiceGenerator () {return new BookServiceImpl (); }

A teraz môžeme načítať inštanciu BookService:

BookService bookService = injector.getInstance (BookService.class); assertNotNull (bookService);

3.5. Skenovanie komponentov Classpath na jar

Jar poskytuje a @ComponentScan anotácia automaticky rozpozná a vytvorí inštanciu komentovaných komponentov skenovaním preddefinovaných balíkov.

The @ComponentScan anotácia informuje Spring, ktoré balíčky budú kontrolované na prítomnosť anotovaných komponentov. Používa sa s @ Konfigurácia anotácia.

3.6. Skenovanie komponentov Classpath v Guice

Na rozdiel od jari Spoločnosť Guice nemá takúto funkciu skenovania komponentov. Nie je ale ťažké to simulovať. Existuje niekoľko doplnkov ako Guvernér ktoré môžu túto funkciu uviesť do Guice.

3.7. Rozpoznávanie objektov na jar

Jar pozná objekty podľa ich mien. Pružina drží predmety v štruktúre, ktorá je zhruba ako a Mapa. To znamená, že nemôžeme mať dva objekty s rovnakým názvom.

Zrážka fazule v dôsledku toho, že máte viac fazúľ s rovnakým názvom, je jeden spoločný problém Vývojári na jar zasiahli. Uvažujme napríklad o nasledujúcich fazulových vyhláseniach:

@Configuration @Import ({SpringBeansConfig.class}) @ComponentScan ("com.baeldung.di.spring") verejná trieda SpringMainConfig {@Bean public BookService bookServiceGenerator () {return new BookServiceImpl (); }}
@Configuration verejná trieda SpringBeansConfig {@Bean public AudioBookService bookServiceGenerator () {vrátiť nový AudioBookServiceImpl (); }}

Ako si pamätáme, pre fazuľu sme už mali definíciu fazule BookService v SpringMainConfig trieda.

Aby sme tu vytvorili fazuľovú kolíziu, musíme deklarovať fazuľové metódy s rovnakým názvom. V jednej triede však nesmieme mať dve rôzne metódy s rovnakým názvom. Z tohto dôvodu sme vyhlásili AudioBookService fazuľa v inej konfiguračnej triede.

Teraz poďme tieto fazule odkázať na jednotkový test:

BookService bookService = context.getBean (BookService.class); assertNotNull (bookService); AudioBookService audioBookService = context.getBean (AudioBookService.class); assertNotNull (audioBookService);

Test jednotky zlyhá s:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Nie je k dispozícii kvalifikačná fazuľa typu „AudioBookService“

Najprv Spring zaregistrovala AudioBookService fazuľa s „BookServiceGenerator“ názov na svojej fazuľovej mape. Potom to muselo prepísať definíciou fazule pre BookService v dôsledku „Nie sú povolené duplicitné mená“ povaha HashMap dátová štruktúra.

Nakoniec tento problém môžeme prekonať tak, že urobíme jedinečné názvy metód fazule alebo nastavíme názov každému z nich prideliť jedinečný názov @Bean.

3.8. Rozpoznávanie objektov v Guice

Na rozdiel od jari Guice má v podstate a Mapa štruktúra. To znamená, že nemôžeme mať viac väzieb na rovnaký typ bez použitia ďalších metadát.

Guice poskytuje anotácie väzieb, aby umožnil definovanie viacerých väzieb pre rovnaký typ. Pozrime sa, čo sa stane, ak budeme mať v Guice dve rôzne väzby pre rovnaký typ.

osoba vo verejnej triede {}

Teraz, poďme vyhlásiť dve rôzne záväzné pre Osoba trieda:

bind (Person.class) .toConstructor (Person.class.getConstructor ()); bind (Person.class) .toProvider (new Provider () {public Person get () {Person p = new Person (); return p;}});

A tu je príklad, ako môžeme získať príklad Osoba trieda:

Osoba osoba = injector.getInstance (Person.class); assertNotNull (osoba);

Toto zlyhá s:

com.google.inject.CreationException: Väzba na osobu bola už nakonfigurovaná na GuiceModule.configure ()

Tento problém môžeme prekonať jednoduchým vyradením jedného z viazaní pre Osoba trieda.

3.9. Voliteľné závislosti na jar

Voliteľné závislosti sú závislosti, ktoré sa nevyžadujú pri automatickom zapojení alebo injekcii fazule.

Pre pole s poznámkou @Autowired, ak sa fazuľa so zodpovedajúcim dátovým typom nenájde v kontexte, Spring hodí NoSuchBeanDefinitionException.

Avšak niekedy môžeme chcieť vynechať automatické zapojenie pre niektoré závislosti a nechať ich ako nulovýbez zrušenia výnimky:

Teraz sa pozrime na nasledujúci príklad:

@ Verejná trieda komponentu BookServiceImpl implementuje BookService {@Autowired private AuthorService authorService; }
verejná trieda AuthorServiceImpl implementuje AuthorService {}

Ako vidíme z vyššie uvedeného kódu, AuthorServiceImpl trieda nebola anotovaná ako komponent. A budeme predpokladať, že v našich konfiguračných súboroch pre ňu neexistuje metóda deklarácie fazule.

Teraz spustíme nasledujúci test, aby sme zistili, čo sa stane:

BookService bookService = context.getBean (BookService.class); assertNotNull (bookService);

Nie je prekvapením, že neuspeje s:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Nie je k dispozícii kvalifikačná fazuľa typu „AuthorService“

Môžeme vyrobiť authorService závislosť voliteľná pomocou Java 8 Voliteľné typu, aby ste sa vyhli tejto výnimke.

verejná trieda BookServiceImpl implementuje BookService {@Autowired private Voliteľný autorService; }

Teraz, náš authorService závislosť je skôr ako kontajner, ktorý môže alebo nemusí obsahovať fazuľu AutorService typu. Aj keď tu nie je fazuľa pre AutorService v našom aplikačnom kontexte náš authorService pole bude stálenulový prázdna nádoba. Jar teda nebude mať dôvod hádzať NoSuchBeanDefinitionException.

Ako alternatíva k Voliteľné, môžeme použiť @Autowired‘S požadovaný atribút, ktorý je nastavený na pravda v predvolenom nastavení je závislosť voliteľná. Môžeme nastaviť požadovaný atribút nepravdivé aby bola závislosť voliteľná pre automatické zapojenie.

Jar preto preskočí vloženie závislosti, ak fazuľa pre svoj dátový typ nie je v kontexte k dispozícii. Závislosť zostane nastavená na nulový:

@ Verejná trieda komponentu BookServiceImpl implementuje BookService {@Autowired (vyžadované = nepravdivé) súkromné ​​AuthorService authorService; }

Niekedy môže byť užitočné označovanie závislostí, pretože nie všetky závislosti sú vždy povinné.

V tejto súvislosti by sme si mali pamätať, že budeme musieť postupovať opatrne a nulový-kontroluje počas vývoja, aby sa zabránilo akejkoľvek NullPointerException v dôsledku nulový závislosti.

3.10. Voliteľné závislosti v Guice

Rovnako ako Jar, Guice môžete tiež použiť Java 8 Voliteľné typu, aby bola závislosť voliteľná.

Povedzme, že chceme vytvoriť triedu s a Foo závislosť:

public class FooProcessor {@Inject private Foo foo; }

Teraz definujme väzbu pre Foo trieda:

bind (Foo.class) .toProvider (new Provider () {public Foo get () {return null;}});

Teraz sa pokúsime získať príklad FooProcessor pri jednotkovej skúške:

FooProcessor fooProcessor = injector.getInstance (FooProcessor.class); assertNotNull (fooProcessor);

Náš test jednotky zlyhá s:

com.google.inject.ProvisionException: null vrátený väzbou na GuiceModule.configure (..), ale 1. parameter FooProcessor. [...] nie je @ Nullable

Aby sme túto výnimku preskočili, môžeme urobiť foo závislosť voliteľná s jednoduchou aktualizáciou:

verejná trieda FooProcessor {@Inject private Voliteľné foo; }

@Inject nemá požadovaný atribút na označenie závislosti voliteľný. Alternatívny prístup k urobiť voliteľnou závislosťou v Guice je použitie @ Nullable anotácia.

Guice toleruje injekčné podávanie nulový hodnoty v prípade použitia @ Nullable ako je vyjadrené v správe o výnimke vyššie. Aplikujme @ Nullable anotácia:

public class FooProcessor {@Inject @Nullable private Foo foo; }

4. Implementácie typov závislých injekcií

V tejto časti sa pozrieme na typy injekcií závislostí a porovnáme implementácie poskytované programami Spring a Guice pomocou niekoľkých príkladov.

4.1. Vstrekovanie konštruktéra na jar

V injektore závislostí založenom na konštruktore odovzdáme požadované závislosti do triedy v čase vytvorenia inštancie.

Povedzme, že chceme mať komponentu Spring a chceme cez jej konštruktor pridať závislosti. Toho konštruktora môžeme anotovať @Autowired:

@ Komponenta verejná trieda SpringPersonService {private PersonDao personDao; @Autowired public SpringPersonService (PersonDao personDao) {this.personDao = personDao; }}

Počnúc jarou 4 sa @Autowired závislosť sa nevyžaduje pre tento typ vstrekovania, ak má trieda iba jedného konštruktora.

Poďme získať a SpringPersonService fazuľa v teste:

SpringPersonService personService = context.getBean (SpringPersonService.class); assertNotNull (personService);

4.2. Constructor Injection v Guice

Predchádzajúci príklad môžeme zmeniť na implementovať injektor konštruktora v Guice. Upozorňujeme, že Guice používa @Inject namiesto @Autowired.

public class GuicePersonService {private PersonDao personDao; @Inject public GuicePersonService (PersonDao personDao) {this.personDao = personDao; }}

Tu je príklad, ako môžeme získať príklad GuicePersonService triedy z injektor v teste:

GuicePersonService personService = injector.getInstance (GuicePersonService.class); assertNotNull (personService);

4.3. Nastavovač alebo vstrekovanie metódy na jar

Pri vkladaní závislostí založených na nastavovači bude kontajner volať nastavovacie metódy triedy po vyvolaní konštruktora na vytvorenie inštancie komponentu.

Povedzme, že chceme, aby Spring automaticky nastavila závislosť pomocou metódy setter. Túto nastavovaciu metódu môžeme anotovať @Autowired:

@ Komponenta verejná trieda SpringPersonService {private PersonDao personDao; @Autowired public void setPersonDao (PersonDao personDao) {this.personDao = personDao; }}

Kedykoľvek potrebujeme príklad SpringPersonService triedy, jar bude autowire osobaDao pole vyvolaním setPersonDao () metóda.

Môžeme dostať a SpringPersonService fazuľa a prístup k jej osobaDao pole v teste, ako je uvedené nižšie:

SpringPersonService personService = context.getBean (SpringPersonService.class); assertNotNull (personService); assertNotNull (personService.getPersonDao ());

4.4. Nastavovač alebo vstrekovanie metódy v Guice

Náš príklad jednoducho trochu zmeníme, aby sme to dosiahli vstrekovač v Guice.

public class GuicePersonService {private PersonDao personDao; @Inject public void setPersonDao (PersonDao personDao) {this.personDao = personDao; }}

Zakaždým, keď dostaneme inštanciu GuicePersonService triedy od injektora, budeme mať osobaDao pole prešlo na nastavovaciu metódu vyššie.

Tu je príklad, ako môžeme vytvoriť inštanciu GuicePersonService triedy a prístup k jej osobaDao lúkav teste:

GuicePersonService personService = injector.getInstance (GuicePersonService.class); assertNotNull (personService); assertNotNull (personService.getPersonDao ());

4.5. Vstrekovanie poľa na jar

Vo všetkých našich príkladoch sme už videli, ako aplikovať injekciu poľa pre Spring aj Guice. Nie je to teda pre nás nový koncept. Poďme si to však pre úplnosť uviesť znova.

V prípade vkladania závislostí založených na poli vkladáme závislosti označením pomocou @Autowired alebo @Inject.

4.6. Vstrekovanie poľa v Guice

Ako sme spomenuli v časti vyššie, už sme pokryli poľné vstrekovanie pre použitie Guice @Inject.

5. Záver

V tomto tutoriáli sme preskúmali niekoľko základných rozdielov medzi rámcami Guice a Spring v spôsoboch implementácie vkladania závislostí. Ako vždy, vzorky kódu Guice a Spring sú na GitHube koniec.


$config[zx-auto] not found$config[zx-overlay] not found