CDI prijenosni produžetak i prelet

1. Pregled

U ovom ćemo uputstvu razmotriti zanimljivu značajku CDI-ja (ubrizgavanje konteksta i ovisnosti) pod nazivom prijenosno proširenje CDI.

Prvo ćemo započeti s razumijevanjem kako to funkcionira, a zatim ćemo vidjeti kako napisati proširenje. Proći ćemo korake za implementaciju CDI integracijskog modula za Flyway, tako da možemo pokrenuti migraciju baze podataka prilikom pokretanja CDI spremnika.

Ovaj vodič pretpostavlja osnovno razumijevanje CDI-a. Pogledajte ovaj članak za uvod u CDI.

2. Što je prijenosno proširenje CDI?

Prijenosno proširenje CDI mehanizam je pomoću kojeg možemo implementirati dodatne funkcije na vrhu CDI spremnika. U vrijeme pokretanja, CDI spremnik skenira put klase i stvara metapodatke o otkrivenim klasama.

Tijekom ovog postupka skeniranja, CDI spremnik aktivira mnoge događaje inicijalizacije koje mogu promatrati samo proširenja. Tu nastupa prijenosno proširenje CDI.

Proširenje CDI Portable promatra ove događaje, a zatim mijenja ili dodaje informacije u metapodatke stvorene u spremniku.

3. Ovisnosti Mavena

Počnimo s dodavanjem potrebne ovisnosti za CDI API u pom.xml. Dovoljno je za implementaciju praznog proširenja.

 javax.enterprise cdi-api 2.0.SP1 

A za pokretanje aplikacije možemo koristiti bilo koju CDI implementaciju koja je u skladu. U ovom ćemo članku koristiti implementaciju zavara.

 org.jboss.weld.se zavarivanje-jezgra 3.0.5.Konačno vrijeme izvođenja 

Možete provjeriti jesu li nove verzije API-ja i implementacije objavljene u Maven Central.

4. Trčanje Flywayom u okruženju koje nije CDI

Prije nego što počnemo integrirati Flyway i CDI, trebali bismo prvo razmotriti kako ga pokrenuti u kontekstu koji nije CDI.

Pa pogledajmo sljedeći primjer preuzet sa službenog web mjesta Flyway:

DataSource dataSource = // ... Put za letenje = novi Flyway (); flyway.setDataSource (dataSource); flyway.migrate ();

Kao što vidimo, koristimo samo Flyway instanci kojoj je potreban a Izvor podataka primjer.

Naše prijenosno proširenje CDI kasnije će proizvesti Flyway i Izvor podataka grah. U svrhu ovog uzorka koristit ćemo ugrađenu H2 bazu podataka i pružit ćemo je Izvor podataka svojstva kroz DataSourceDefinition bilješka.

5. Događaji inicijalizacije CDI spremnika

Na bootstrapu aplikacije, CDI spremnik započinje učitavanjem i instanciranjem svih CDI prijenosnih proširenja. Zatim u svakom proširenju pretražuje i registrira promatračke metode inicijalizacijskih događaja ako postoje. Nakon toga izvodi sljedeće korake:

  1. Vatre BeforeBeanDiscovery događaj prije početka postupka skeniranja
  2. Izvršava otkrivanje tipa u kojem skenira arhivski grah i za svaki otkriveni tip aktivira ProcessAnnotatedType događaj
  3. Pali AfterTypeDiscovery događaj
  4. Obavlja otkrivanje graha
  5. Pali AfterBeanDiscovery događaj
  6. Izvodi provjeru graha i otkriva pogreške u definiciji
  7. Pali AfterDeploymentValidation događaj

Namjera prijenosnog proširenja CDI-a je zatim promatrati ove događaje, provjeriti metapodatke o otkrivenom grahu, modificirati ove metapodatke ili ih dodati.

U prijenosnom proširenju CDI-a možemo promatrati samo ove događaje.

6. Pisanje prijenosnog proširenja CDI

Pogledajmo kako se možemo uključiti u neke od ovih događaja izgradnjom vlastitog prijenosnog proširenja CDI.

6.1. Implementacija dobavljača SPI

Prijenosno proširenje CDI je Java SPI davatelj sučelja javax.enterprise.inject.spi.Extension. Pogledajte ovaj članak za uvod u Java SPI.

Prvo započinjemo pružanjem Proširenje provedba. Kasnije ćemo dodati metode promatrača u događaje bootstrapa CDI spremnika:

javna klasa FlywayExtension implementira proširenje {}

Zatim dodamo naziv datoteke META-INF / usluge / javax.enterprise.inject.spi.Proširenje sa ovim sadržajem:

com.baeldung.cdi.extention.FlywayExtension

Kao SPI, ovo Proširenje se učitava prije pokretanja spremnika. Tako se mogu registrirati metode promatrača na CDI bootstrap događajima.

6.2. Definiranje promatračkih metoda događaja inicijalizacije

U ovom primjeru izrađujemo Flyway razred poznat CDI spremniku prije nego započne postupak skeniranja. To je učinjeno u registerFlywayType () metoda promatrača:

javni void registerFlywayType (@Observations BeforeBeanDiscovery bbdEvent) {bbdEvent.addAnnotatedType (Flyway.class, Flyway.class.getName ()); }

Ovdje smo dodali metapodatke o Flyway razred. Od sada će se ponašati kao da ga je skenirao spremnik. U tu svrhu koristili smo addAnnotatedType () metoda.

Dalje ćemo promatrati ProcessAnnotatedType događaj da bi se Flyway klasa kao CDI upravljani grah:

javna void processAnnotatedType (@Observations ProcessAnnotatedType patEvent) {patEvent.configureAnnotatedType () .add (ApplicationScoped.Literal.INSTANCE) .add (new AnnotationLiteral () {}) .filterMethods (annotatedMetomet -> method. ) == 1 && annotatedMethod.getParameters (). Get (0) .getBaseType () .equals (javax.sql.DataSource.class);}). FindFirst (). Get (). Add (InjectLiteral.INSTANCE); }

Prvo, bilježimo Flyway razred sa @ApplicationScoped i @FlywayType napomene, zatim pretražujemo Flyway.setDataSource (DataSource dataSource) metodu i bilježimo je pomoću @Ubrizgati.

Konačni rezultat gore navedenih operacija ima isti učinak kao da spremnik skenira sljedeće Flyway grah:

@ApplicationScoped @FlywayType javna klasa Flyway {// ... @Inject public void setDataSource (DataSource dataSource) {// ...}}

Sljedeći je korak zatim napraviti a Izvor podataka grah dostupan za injekcije kao naš Flyway grah ovisi o a Izvor podataka grah.

Za to ćemo obraditi registraciju a Izvor podataka Zrnite grah u posudu i koristit ćemo AfterBeanDiscovery događaj:

void afterBeanDiscovery (@Observa AfterBeanDiscovery abdEvent, BeanManager bm) {abdEvent.addBean () .types (javax.sql.DataSource.class, DataSource.class) .qualifiers (new AnnotationLiteral () {}, new AnnatationLiteral () {}, new AnnatationLiteral ()}}, new AnnotationLiteral () {}, new opseg (ApplicationScoped.class) .name (DataSource.class.getName ()) .beanClass (DataSource.class) .createWith (creationalContext -> {DataSource instance = new DataSource (); instance.setUrl (dataSourceDefinition.url ()); instance.setDriverClassName (dataSourceDefinition.className ()); vrati instancu;}); }

Kao što vidimo, trebamo DataSourceDefinition koji pruža svojstva DataSource.

Bilo koji upravljani grah možemo označiti sljedećom bilješkom:

@DataSourceDefinition (name = "ds", className = "org.h2.Driver", url = "jdbc: h2: mem: testdb")

Da bismo izdvojili ta svojstva, promatramo ProcessAnnotatedType događaj zajedno s @WithAnnotations napomena:

javna praznina identifyDataSourceDefinition (@Observations @WithAnnotations (DataSourceDefinition.class) ProcessAnnotatedType patEvent) {AnnotatedType at = patEvent.getAnnotatedType (); dataSourceDefinition = at.getAnnotation (DataSourceDefinition.class); }

I na kraju, slušamo AfterDeployementValidation događaj da biste dobili željeno Flyway grah iz CDI spremnika, a zatim pozovite migrirati() metoda:

void runFlywayMigration (@Observations AfterDeploymentValidation adv, BeanManager manager) {Flyway flyway = manager.createInstance () .select (Flyway.class, new AnnotationLiteral () {}). get (); flyway.migrate (); }

7. Zaključak

Izgradnja prijenosnog proširenja CDI čini se da je u početku teško, ali kad shvatimo životni ciklus inicijalizacije spremnika i SPI posvećen proširenjima, postaje vrlo moćan alat koji možemo koristiti za izgradnju okvira na vrhu Jakarte EE.

Kao i obično, svi uzorci koda prikazani u ovom članku mogu se naći na GitHubu.


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