Prenosné rozšírenie CDI a Flyway

1. Prehľad

V tomto výučbe si ukážeme zaujímavú vlastnosť CDI (Context and Dependency Injection) s názvom CDI portable extension.

Najprv začneme pochopením toho, ako to funguje, a potom uvidíme, ako napísať príponu. Prejdeme si kroky implementácie integračného modulu CDI pre Flyway, aby sme mohli spustiť migráciu databázy pri štarte kontajnera CDI.

Tento tutoriál predpokladá základné pochopenie CDI. V tomto článku nájdete úvod do CDI.

2. Čo je to prenosné rozšírenie CDI?

Prenosné rozšírenie CDI je mechanizmus, pomocou ktorého môžeme implementovať ďalšie funkcie navrch kontajnera CDI. V čase bootstrapu kontajner CDI skenuje cestu k triede a vytvára metadáta o objavených triedach.

Počas tohto procesu skenovania kontajner CDI spustí veľa inicializačných udalostí, ktoré je možné pozorovať iba pomocou rozšírení. Tu prichádza na rad prenosné rozšírenie CDI.

Prenosné rozšírenie CDI sleduje tieto udalosti a potom upravuje alebo pridáva informácie k metaúdajom vytvoreným kontajnerom.

3. Závislosti Maven

Začnime pridaním požadovanej závislosti pre CDI API v pom.xml. Je to dostatočné na implementáciu prázdneho rozšírenia.

 javax.enterprise cdi-api 2.0.SP1 

A na spustenie aplikácie môžeme použiť akúkoľvek kompatibilnú implementáciu CDI. V tomto článku použijeme implementáciu Weld.

 org.jboss.weld.se weld-se-core 3.0.5. Konečný čas behu 

Môžete skontrolovať, či boli vydané nejaké nové verzie API a implementácie v Maven Central.

4. Spustenie Flyway v prostredí, ktoré nie je CDI

Predtým, ako začneme integráciu Flyway a CDI, mali by sme sa najskôr pozrieť na to, ako to spustiť v kontexte, ktorý nie je CDI.

Poďme sa teda pozrieť na nasledujúci príklad prevzatý z oficiálnej stránky Flyway:

DataSource dataSource = // ... Flyway flyway = nový Flyway (); flyway.setDataSource (dataSource); flyway.migrate ();

Ako vidíme, používame iba a Flyway inštancia, ktorá potrebuje a Dátový zdroj inštancia.

Naše prenosné rozšírenie CDI bude neskôr vyrábať Flyway a Dátový zdroj fazuľa. Na účely tejto vzorky použijeme vloženú databázu H2 a poskytneme ju Dátový zdroj vlastnosti prostredníctvom DataSourceDefinition anotácia.

5. Udalosti inicializácie kontajnera CDI

Pri bootstrape aplikácie sa kontajner CDI začína načítaním a vytvorením inštancie všetkých prenosných rozšírení CDI. Potom v každej prípone prehľadá a zaregistruje pozorovateľské metódy inicializačných udalostí, ak existujú. Potom vykoná nasledujúce kroky:

  1. Požiare BeforeBeanDiscovery pred začatím procesu skenovania
  2. Vykoná zisťovanie typov, pri ktorých skenuje archívne fazule, a pre každý zistený typ spustí ProcessAnnotatedType udalosť
  3. Požiare AfterTypeDiscovery udalosť
  4. Vykoná objav fazule
  5. Požiare AfterBeanDiscovery udalosť
  6. Vykoná validáciu fazule a zistí chyby v definícii
  7. Požiare AfterDeploymentValidation udalosť

Zámerom prenosného rozšírenia CDI je potom pozorovať tieto udalosti, skontrolovať metadáta o objavených fazuľach, upraviť tieto metadáta alebo ich pridať.

V prenosnom rozšírení CDI môžeme tieto udalosti iba pozorovať.

6. Písanie prenosného rozšírenia CDI

Pozrime sa, ako sa môžeme zapojiť do niektorých z týchto udalostí vytvorením vlastného prenosného rozšírenia CDI.

6.1. Implementácia poskytovateľa SPI

Prenosné rozšírenie CDI je poskytovateľom rozhrania Java SPI javax.enterprise.inject.spi.Extension. V tomto článku nájdete úvod do Java SPI.

Najprv začneme poskytovaním Predĺženie implementácia. Neskôr pridáme pozorovacie metódy k udalostiam bootstrapu kontajnera CDI:

verejná trieda FlywayExtension implementuje rozšírenie {}

Potom pridáme názov súboru META-INF / services / javax.enterprise.inject.spi.Extension s týmto obsahom:

com.baeldung.cdi.extension.FlywayExtension

Ako SPI toto Predĺženie sa načíta pred bootstrapom kontajnera. Je teda možné zaregistrovať pozorovacie metódy na udalostiach bootstrap CDI.

6.2. Definovanie pozorovacích metód inicializačných udalostí

V tomto príklade robíme Flyway trieda známa kontajneru CDI pred začiatkom procesu skenovania. To sa deje v registerFlywayType () metóda pozorovateľa:

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

Tu sme pridali metadáta o Flyway trieda. Odteraz sa bude správať, akoby ho skenoval kontajner. Na tento účel sme použili addAnnotatedType () metóda.

Ďalej budeme pozorovať ProcessAnnotatedType udalosť urobiť Flyway triedy ako fazuľa riadená CDI:

public void processAnnotatedType (@Observes ProcessAnnotatedType patEvent) {patEvent.configureAnnotatedType () .add (ApplicationScoped.Literal.INSTANCE) .add (new AnnotationLiteral () {}) .filterMethods (annotatedMethod -> {return annotatedMethod -> {návrat ) == 1 && annotatedMethod.getParameters (). Get (0) .getBaseType () .equals (javax.sql.DataSource.class);}). FindFirst (). Get (). Add (InjectLiteral.INSTANCE); }

Najskôr anotujeme Flyway trieda s @ApplicationScoped a @FlywayType anotácie, potom prehľadáme Flyway.setDataSource (DataSource dataSource) metódou a anotujeme ju @Inject.

Konečný výsledok vyššie uvedených operácií má rovnaký efekt, ako keby kontajner skenoval nasledujúce Flyway fazuľa:

@ApplicationScoped @FlywayType verejná trieda Flyway {// ... @Inject public void setDataSource (DataSource dataSource) {// ...}}

Ďalším krokom je potom príprava a Dátový zdroj fazuľa k dispozícii na injekciu ako naša Flyway fazuľa závisí od a Dátový zdroj fazuľa.

Za týmto účelom spracujeme registráciu a Dátový zdroj Fazuľa do nádoby a my použijeme AfterBeanDiscovery udalosť:

void afterBeanDiscovery (@Observes AfterBeanDiscovery abdEvent, BeanManager bm) {abdEvent.addBean () .types (javax.sql.DataSource.class, DataSource.class) .qualifiers (new AnnotationLiteral () {}, new AnnotationLiteral () {}). scope (ApplicationScoped.class) .name (DataSource.class.getName ()) .beanClass (DataSource.class) .createWith (creationalContext -> {DataSource instance = new DataSource (); instance.setUrl (dataSourceDefinition.url ()); instance.setDriverClassName (dataSourceDefinition.className ()); návratová inštancia;}); }

Ako vidíme, potrebujeme a DataSourceDefinition ktorý poskytuje vlastnosti DataSource.

Môžeme anotovať akékoľvek spravované fazule s nasledujúcou anotáciou:

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

Na extrahovanie týchto vlastností sledujeme ProcessAnnotatedType udalosť spolu s @WithAnnotations anotácia:

public void detectDataSourceDefinition (@Observes @WithAnnotations (DataSourceDefinition.class) ProcessAnnotatedType patEvent) {AnnotatedType at = patEvent.getAnnotatedType (); dataSourceDefinition = at.getAnnotation (DataSourceDefinition.class); }

A nakoniec si vypočujeme AfterDeployementValidation udalosť na získanie hľadaného Flyway fazuľa z kontajnera CDI a potom vyvolajte migrovať() metóda:

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

7. Záver

Vytvorenie prenosného rozšírenia CDI sa na prvý pohľad zdá byť zložité, ale akonáhle pochopíme životný cyklus inicializácie kontajnera a SPI venovaný rozšíreniam, stane sa veľmi účinným nástrojom, ktorý môžeme použiť na zostavenie rámcov na vrchole Jakarty EE.

Ako obvykle, všetky ukážky kódu zobrazené v tomto článku nájdete na GitHub.


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