Guice vs proljeće - ubrizgavanje ovisnosti

1. Uvod

Google Guice i Proljeće dva su robusna okvira koja se koriste za ubrizgavanje ovisnosti. Oba okvira pokrivaju sve pojmove ubrizgavanja ovisnosti, ali svaki ima svoj način njihove primjene.

U ovom uputstvu razgovarat ćemo o tome kako se okviri Guice i Spring razlikuju u konfiguraciji i implementaciji.

2. Ovisnosti Mavena

Započnimo dodavanjem ovisnosti Guice i Spring Maven u našu pom.xml datoteka:

 org.springframework spring-context 5.1.4.Opusti com.google.inject guice 4.2.2 

Uvijek možemo pristupiti najnovijim proljeće-kontekst ili pretpostavka ovisnosti iz Maven Central.

3. Konfiguracija ubrizgavanja ovisnosti

Ubrizgavanje ovisnosti je tehnika programiranja koju koristimo kako bismo svoje predavanja učinili neovisnima o njihovim ovisnostima.

U ovom ćemo se dijelu osvrnuti na nekoliko osnovnih značajki koje se razlikuju između Springa i Guicea u njihovim načinima konfiguriranja uvođenja ovisnosti.

3.1. Proljetno ožičenje

Spring deklarira konfiguracije uvođenja ovisnosti u posebnu konfiguracijsku klasu. Ova klasa mora biti označena znakom @Konfiguracija bilješka. Spremnik Spring koristi ovu klasu kao izvor definicija graha.

Predavanja kojima upravlja Proljeće nazivaju seProljetni grah.

Proljeće koristi @Autowired napomena za automatsko povezivanje ovisnosti. @Autowired dio je Spring-ovih ugrađenih jezgrovitih bilješki. Možemo koristiti @Autowired o članskim varijablama, metodama postavljanja i konstruktorima.

Proljeće također podržava @Ubrizgati. @Ubrizgati dio je Java CDI (Contexts and Dependency Injection) koji definira standard za ubrizgavanje ovisnosti.

Recimo da želimo automatski povezati ovisnost s varijablom člana. To možemo jednostavno označiti s @Autowired:

@Component javna klasa UserService {@Autowired private AccountService accountService; }
@Component javna klasa AccountServiceImpl implementira AccountService {}

Drugo, stvorimo klasu konfiguracije koja će se koristiti kao izvor graha tijekom učitavanja konteksta naše aplikacije:

@Configuration @ComponentScan ("com.baeldung.di.spring") javna klasa SpringMainConfig {}

Imajte na umu da smo također dodali bilješke Korisnička usluga i AccountServiceImpl s @Komponenta da ih registriraju kao grah. To je @ComponentScan napomena koja će proljeću reći gdje tražiti za komentirane komponente.

Iako smo bilježili AccountServiceImpl,Proljeće ga može preslikati na AccountService budući da provodi AccountService.

Zatim, moramo definirati kontekst aplikacije za pristup grahu. Napomenimo samo da ćemo se na ovaj kontekst pozivati ​​u svim našim proljetnim jediničnim testovima:

ApplicationContext context = new AnnotationConfigApplicationContext (SpringMainConfig.class);

Sada za vrijeme izvođenja možemo dohvatiti AccountService primjer iz našeg Korisnička usluga grah:

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

3.2. Povezivanje Guicea

Guice upravlja svojim ovisnostima u posebnoj klasi koja se naziva modul. Guiceov modul mora proširiti AbstractModule klase i nadjačati njezinu konfigurirati() metoda.

Guice koristi vezivanje kao ekvivalent ožičenju u proljeće. Jednostavno rečeno, vezovi nam omogućuju da definiramo kako će se ovisnosti ubrizgavati u klasu. Veze Guice deklarirane su u našim modulima konfigurirati() metoda.

Umjesto @Autowired, Guice koristi @Ubrizgati napomena za ubrizgavanje ovisnosti.

Stvorimo ekvivalentan Guiceov primjer:

javna klasa GuiceUserService {@Inject private AccountService accountService; }

Drugo, stvorit ćemo klasu modula koja je izvor naših definicija vezanja:

javna klasa GuiceModule proširuje AbstractModule {@Override protected void configure () {bind (AccountService.class) .to (AccountServiceImpl.class); }}

Uobičajeno očekujemo od Guicea da instancira svaki objekt ovisnosti iz njihovih zadanih konstruktora ako u bilo kojem vezi nije izričito definirano konfigurirati() metoda. Ali budući da se sučelja ne mogu izravno instancirati, moramo definirati povezivanja kako bi rekao Guiceu koje će sučelje biti upareno s kojom implementacijom.

Zatim, moramo definirati Injektor koristeći GuiceModule kako bismo dobili primjerke naših predavanja. Napomenimo samo da će svi naši Guice testovi to koristiti Injektor:

Injector injector = Guice.createInjector (novi GuiceModule ());

Napokon, za vrijeme izvođenja dohvaćamo a GuiceUserService primjer s ne-null accountService ovisnost:

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

3.3. Proljetna bilješka @Bean

Spring također nudi bilješku na razini metode @Grah registrirati grah kao alternativa svojim napomenama na razini klase poput @Komponenta. Povratna vrijednost a @Grah anotirana metoda registrira se kao grah u spremniku.

Recimo da imamo primjerak BookServiceImpl koje želimo učiniti dostupnima za injekcije. Mogli bismo koristiti @Grah za registraciju naše instance:

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

A sada možemo dobiti i BookService grah:

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

3.4. Guice's @Provides Annotation

Kao ekvivalent Proljeća @Grah napomena, Guice ima ugrađenu napomenu @Provides raditi isti posao. Kao @Grah, @Provides primjenjuje se samo na metode.

Sada ćemo implementirati prethodni primjer graha proljeća s Guiceom. Sve što trebamo učiniti je dodati sljedeći kod u našu klasu modula:

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

A sada, možemo pronaći primjerak BookService:

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

3.5. Skeniranje komponente Classpath u proljeće

Proljeće pruža a @ComponentScan anotacija automatski otkriva i instancira označene komponente skeniranjem unaprijed definiranih paketa.

The @ComponentScan napomena govori Springu koji će se paketi skenirati u vezi s označenim komponentama. Koristi se sa @Konfiguracija bilješka.

3.6. Skeniranje komponente Classpath u Guiceu

Za razliku od proljeća, Guice nema takvu značajku skeniranja komponenata. Ali nije teško to simulirati. Postoje neki dodaci poput Guverner koji ovu značajku mogu unijeti u Guice.

3.7. Prepoznavanje predmeta u proljeće

Proljeće prepoznaje predmete po imenima. Proljeće drži predmete u strukturi koja je otprilike poput Karta. To znači da ne možemo imati dva objekta s istim imenom.

Čest je problem sudara graha zbog više graha istog imena Pogodili proljetni programeri. Na primjer, uzmimo u obzir sljedeće deklaracije graha:

@Configuration @Import ({SpringBeansConfig.class}) @ComponentScan ("com.baeldung.di.spring") javna klasa SpringMainConfig {@Bean public BookService bookServiceGenerator () {return new BookServiceImpl (); }}
@Configuration javna klasa SpringBeansConfig {@Bean public AudioBookService bookServiceGenerator () {return new AudioBookServiceImpl (); }}

Kao što se sjećamo, već smo imali definiciju graha za BookService u SpringMainConfig razred.

Da bismo ovdje stvorili sudar graha, moramo deklarirati metode graha s istim imenom. No, u jednom razredu ne smijemo imati dvije različite metode s istim nazivom. Iz tog razloga proglasili smo AudioBookService grah u drugoj klasi konfiguracije.

Sad, uputimo ove grah u jedinični test:

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

Jedinstveni test neće uspjeti sa:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Nije dostupan kvalificirani grah tipa 'AudioBookService'

Prvo je Spring registrirao AudioBookService grah sa “BookServiceGenerator” ime na svojoj karti graha. Zatim, to je moralo nadjačati definicijom graha za BookService zbog “Nisu dopuštena duplikata imena” priroda HashMap struktura podataka.

Posljednje, ovaj problem možemo prevladati tako da imena metoda graha učinimo jedinstvenima ili postavimo Ime atribut jedinstvenom imenu za svaku @Grah.

3.8. Prepoznavanje predmeta u Guiceu

Za razliku od proljeća, Guice u osnovi ima Karta struktura. To znači da ne možemo imati više veza na isti tip bez upotrebe dodatnih metapodataka.

Guice nudi bilješke vezanja kako bi omogućio definiranje više veza za isti tip. Pogledajmo što će se dogoditi ako imamo dva različita vezanja za isti tip u Guiceu.

Javna klasa Osoba {}

Sada, proglasimo dva različita obvezujuća za Osoba razred:

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

I evo kako možemo dobiti primjerak Osoba razred:

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

Ovo neće uspjeti sa:

com.google.inject.CreationException: Vezanje za osobu već je konfigurirano na GuiceModule.configure ()

Ovaj problem možemo prevladati jednostavnim odbacivanjem jednog od veza za Osoba razred.

3.9. Izborne ovisnosti u proljeće

Neobavezne ovisnosti su ovisnosti koje nisu potrebne prilikom automatskog ožičenja ili ubrizgavanja graha.

Za polje koje je označeno s @Autowired, ako grah s odgovarajućim tipom podataka nije pronađen u kontekstu, Spring će baciti NoSuchBeanDefinitionException.

Međutim, ponekad bismo mogli preskočiti automatsko povezivanje radi nekih ovisnosti i ostaviti ih kao nullbez izbacivanja iznimke:

Sada ćemo pogledati sljedeći primjer:

@Component javna klasa BookServiceImpl implementira BookService {@Autowired private AuthorService authorService; }
javna klasa AuthorServiceImpl implementira AuthorService {}

Kao što vidimo iz gornjeg koda, AuthorServiceImpl razred nije označen kao komponenta. Pretpostavit ćemo da u našim konfiguracijskim datotekama za to ne postoji metoda deklariranja graha.

A sad, pokrenimo sljedeći test da vidimo što će se dogoditi:

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

Nije iznenađujuće što neće uspjeti sa:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Nije dostupan kvalificirani grah tipa 'AuthorService'

Možemo napraviti autorUsluga ovisnost neobavezna korištenjem Jave 8 Neobvezno upišite kako biste izbjegli ovu iznimku.

javna klasa BookServiceImpl implementira BookService {@Autowired private Neobvezna authorService; }

Sada, naš autorUsluga ovisnost je više poput spremnika koji može sadržavati zrno graha ili ne AutorServis tip. Iako ne postoji grah za AutorServis u našem kontekstu aplikacije, naš autorUsluga polje će i dalje bitinull prazna posuda. Stoga Proljeće neće imati razloga za bacanje NoSuchBeanDefinitionException.

Kao alternativa Neobvezno, možemo koristiti @Autowired‘S potreban atribut, koji je postavljen na pravi prema zadanim postavkama, da bi ovisnost postala neobavezna. Možemo postaviti potreban pripisati lažno kako bi ovisnost postala neobavezna za automatsko ožičenje.

Stoga će Spring preskočiti ubrizgavanje ovisnosti ako grah za njegov tip podataka nije dostupan u kontekstu. Ovisnost će i dalje biti postavljena null:

@Component javna klasa BookServiceImpl provodi BookService {@Autowired (potrebno = netačno) private AuthorService authorService; }

Ponekad označavanje ovisnosti neobvezno može biti korisno jer nisu uvijek potrebne sve ovisnosti.

Imajući ovo na umu, trebali bismo imati na umu da trebamo biti oprezni i null-provjere tijekom razvoja kako bi se izbjegle bilo kakve NullPointerException zbog null ovisnosti.

3.10. Izborne ovisnosti u Guiceu

Baš kao Proljeće, Guice također mogu koristiti Javu 8 Neobvezno upišite da ovisnost postane neobavezna.

Recimo da želimo stvoriti razred i s a Foo ovisnost:

javna klasa FooProcessor {@Inject private Foo foo; }

Sada, definirajmo vezanje za Foo razred:

bind (Foo.class) .toProvider (novi pružatelj () {public Foo get () {return null;}});

Pokušajmo sada dobiti primjerak FooProcessor u jediničnom testu:

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

Naš jedinični test neće uspjeti sa:

com.google.inject.ProvisionException: nula je vraćena vezanjem na GuiceModule.configure (..), ali 1. parametar FooProcessor. [...] nije @Nullable

Da bismo preskočili ovu iznimku, možemo napraviti foo ovisnost neobavezna uz jednostavno ažuriranje:

javna klasa FooProcessor {@Inject private Neobvezno foo; }

@Ubrizgati nema a potreban atribut za označavanje ovisnosti neobavezno. Alternativni pristup napraviti neovisna ovisnost u Guiceu je korištenje @Nullable bilješka.

Guice tolerira ubrizgavanje null vrijednosti u slučaju korištenja @Nullable kako je izraženo u gornjoj poruci o iznimci. Primijenimo @Nullable napomena:

javna klasa FooProcessor {@Inject @Nullable private Foo foo; }

4. Implementacije vrsta ubrizgavanja u ovisnost

U ovom ćemo odjeljku pogledati vrste ubrizgavanja ovisnosti i usporediti implementacije koje pružaju Spring i Guice prolazeći kroz nekoliko primjera.

4.1. Injektiranje konstruktora u proljeće

U ubrizgavanju ovisnosti temeljenom na konstruktoru, prenosimo tražene ovisnosti u klasu u trenutku instanciranja.

Recimo da želimo imati komponentu Spring i želimo dodati ovisnosti kroz njen konstruktor. Taj konstruktor možemo označiti s @Autowired:

@Component javna klasa SpringPersonService {private PersonDao personDao; @Autowired public SpringPersonService (PersonDao personDao) {this.personDao = personDao; }}

Počevši od proljeća 4, @Autowired ovisnost nije potrebna za ovu vrstu ubrizgavanja ako klasa ima samo jedan konstruktor.

Dohvatimo a SpringPersonService grah u testu:

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

4.2. Injekcija konstruktora u Guiceu

Možemo preurediti prethodni primjer u implementirati ubrizgavanje konstruktora u Guice. Imajte na umu da Guice koristi @Ubrizgati umjesto @Autowired.

javna klasa GuicePersonService {private PersonDao personDao; @ Ubrizgajte javni GuicePersonService (PersonDao personDao) {this.personDao = personDao; }}

Evo kako možemo dobiti primjerak GuicePersonService razred iz injektor u testu:

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

4.3. Setter ili injekcija metode u proljeće

U ubrizgavanju ovisnosti temeljenom na postavljaču, spremnik će pozvati metode postavljača klase, nakon što pozove konstruktor da instantira komponentu.

Recimo da želimo da Spring automatski poveže ovisnost pomoću metode postavljača. Tu metodu postavljanja možemo označiti s @Autowired:

@Component javna klasa SpringPersonService {private PersonDao personDao; @Autowired javna praznina setPersonDao (PersonDao personDao) {this.personDao = personDao; }}

Kad god nam zatreba instanca SpringPersonService razreda, Spring će automatski spojiti personDao polje pozivanjem na setPersonDao () metoda.

Možemo dobiti SpringPersonService grah i pristupiti njegovom personDao polje u testu kao dolje:

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

4.4. Setter ili injekcija metode u Guiceu

Jednostavno ćemo malo promijeniti svoj primjer da bismo ga postigli injekcija setera u Guiceu.

javna klasa GuicePersonService {private PersonDao personDao; @ Ubrizgavanje javne praznine setPersonDao (PersonDao personDao) {this.personDao = personDao; }}

Svaki put kad dobijemo primjerak GuicePersonService klase iz mlaznice, imat ćemo personDao polje proslijeđeno gornjoj metodi postavljača.

Evo kako možemo stvoriti instancu GuicePersonService klase i pristupiti njenom personDao poljeu testu:

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

4.5. Ubrizgavanje polja u proljeće

Već smo vidjeli kako primijeniti ubrizgavanje polja za Spring i Guice u svim našim primjerima. Dakle, to za nas nije novi koncept. Ali samo da ga ponovno navedemo radi cjelovitosti.

U slučaju ubrizgavanja ovisnosti na terenu ubrizgavamo ovisnosti označavajući ih @Autowired ili @Ubrizgati.

4.6. Ubrizgavanje polja u Guice

Kao što smo spomenuli u gornjem odjeljku, već smo obradili terenska injekcija za Guice koristeći @Ubrizgati.

5. Zaključak

U ovom smo tutorijalu istražili nekoliko osnovnih razlika između okvira Guice i Spring u njihovim načinima primjene injekcije ovisnosti. Kao i uvijek, uzorci koda Guice i Spring na GitHub-u su gotovi.


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