CDI hordozható kiterjesztés és repülõút

1. Áttekintés

Ebben az oktatóanyagban áttekintjük a CDI (Context and Dependency Injection) érdekes tulajdonságát, a CDI hordozható kiterjesztést.

Először azzal kezdjük, hogy megértsük a működését, majd meglátjuk, hogyan kell írni egy kiterjesztést. Végig fogjuk hajtani a CDI integrációs modul Flyway megvalósításának lépéseit, így egy adatbázis-migrációt futtathatunk egy CDI-tároló indításakor.

Ez az oktatóanyag feltételezi a CDI alapvető ismereteit. A CDI bemutatásához tekintse meg ezt a cikket.

2. Mi az a CDI hordozható kiterjesztés?

A hordozható CDI kiterjesztés olyan mechanizmus, amellyel további funkciókat tudunk megvalósítani a CDI konténer tetején. Indításkor a CDI tároló beolvassa az osztályútvonalat, és metaadatokat készít a felfedezett osztályokról.

A beolvasási folyamat során a CDI-tároló sok inicializálási eseményt indít el, amelyeket csak a kiterjesztések figyelhetnek meg. Itt jelenik meg a CDI hordozható kiterjesztés.

A CDI Portable kiterjesztés figyeli ezeket az eseményeket, majd módosítja vagy hozzáadja az információkat a tároló által létrehozott metaadatokhoz.

3. Maven-függőségek

Kezdjük azzal, hogy hozzáadjuk a CDI API szükséges függőségét a pom.xml. Ez elég egy üres kiterjesztés megvalósításához.

 javax.enterprise cdi-api 2.0.SP1 

Az alkalmazás futtatásához pedig bármilyen kompatibilis CDI megvalósítást használhatunk. Ebben a cikkben a Weld megvalósítást fogjuk használni.

 org.jboss.weld.se hegesztett se-core 3.0.5.Végső futási idő 

A Maven Centralon ellenőrizheti, hogy az API és az implementáció új verziói megjelentek-e.

4. Repülőút futtatása nem CDI környezetben

Mielőtt nekilátnánk az integrációnak Repülőút és a CDI, először meg kell vizsgálnunk, hogyan futtassuk nem CDI kontextusban.

Vessünk egy pillantást az alábbi hivatalos példára, amely a Repülőút:

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

Mint láthatjuk, csak a-t használjuk Repülőút példány, amelyre szükség van a Adatforrás példa.

A CDI hordozható kiterjesztésünk később elkészíti a Repülőút és Adatforrás bab. A minta alkalmazásához beágyazott H2 adatbázist fogunk használni, és megadjuk Adatforrás tulajdonságait a DataSourceDefinition annotáció.

5. CDI konténer inicializálási események

Az alkalmazás indításakor a CDI-tároló az összes CDI hordozható kiterjesztés betöltésével és példányosításával indul. Ezután minden kiterjesztésben megkeresi és regisztrálja az inicializálási események megfigyelői módszereit, ha vannak ilyenek. Ezt követően a következő lépéseket hajtja végre:

  1. Tűz BeforeBeanDiscovery esemény a szkennelési folyamat megkezdése előtt
  2. Elvégzi azt a típusfelfedezést, amelyben az archív babokat beolvassa, és minden felfedezett típusra lő ProcessAnnotatedType esemény
  3. Tűz a AfterTypeDiscovery esemény
  4. Végzi a bab felfedezését
  5. Tűz a AfterBeanDiscovery esemény
  6. Végzi a bab ellenőrzését és észleli a definíciós hibákat
  7. Tűz a AfterDeploymentValidation esemény

A CDI hordozható kiterjesztés célja ezután megfigyelni ezeket az eseményeket, ellenőrizni a felfedezett babok metaadatait, módosítani vagy kiegészíteni ezeket.

Egy CDI hordozható kiterjesztésben csak ezeket az eseményeket figyelhetjük meg.

6. A CDI Portable Extension írása

Lássuk, hogyan tudunk bekapcsolódni néhány ilyen eseménybe saját CDI hordozható kiterjesztésünk megépítésével.

6.1. Az SPI-szolgáltató megvalósítása

A CDI hordozható kiterjesztés a felület Java SPI szolgáltatója javax.enterprise.inject.spi.Extension. A Java SPI bemutatásához olvassa el ezt a cikket.

Először a Kiterjesztés végrehajtás. Később megfigyelő módszereket adunk a CDI tároló bootstrap eseményeihez:

nyilvános osztályú FlywayExtension valósítja meg a kiterjesztést {}

Ezután hozzáadunk egy fájlnevet META-INF / services / javax.enterprise.inject.spi.Extension ezzel a tartalommal:

com.baeldung.cdi.extension.FlywayExtension

SPI-ként ez Kiterjesztés a konténer csomagtartója előtt töltődik be. Tehát megfigyelő módszerek regisztrálhatók a CDI bootstrap eseményein.

6.2. Az események inicializálásának megfigyelői módszereinek meghatározása

Ebben a példában a Repülőút osztály, amelyet a CDI konténer ismert a beolvasás megkezdése előtt. Ez a registerFlywayType () megfigyelő módszer:

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

Itt metaadatokat adtunk a Repülőút osztály. Mostantól úgy fog viselkedni, mintha a tároló vizsgálta volna meg. Erre a célra használtuk a addAnnotatedType () módszer.

Ezután megfigyeljük a ProcessAnnotatedType esemény, hogy a Repülőút osztály CDI kezelt babként:

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

Először feljegyezzük a Repülőút osztályban @ApplicationScoped és @FlywayType annotációk, majd a Flyway.setDataSource (DataSource dataSource) módszerrel és annotáljuk @ Injekció.

A fenti műveletek végeredményének ugyanaz a hatása, mintha a tároló a következőket vizsgálná Repülőút bab:

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

A következő lépés az, hogy a Adatforrás az injekcióhoz kapható bab Repülőút bab függ a Adatforrás bab.

Ehhez feldolgozzuk a Adatforrás Bean a tartályba, és mi használjuk a AfterBeanDiscovery esemény:

void afterBeanDiscovery (@Observes AfterBeanDiscovery abdEvent, BeanManager bm) {abdEvent.addBean () .types (javax.sql.DataSource.class, DataSource.class) .qualifiers (új AnnotationLiteral () {}, új AnnotationLiteral () hatókör (ApplicationScoped.class) .name (DataSource.class.getName ()) .beanClass (DataSource.class) .createWith (creationalContext -> {DataSource példány = új DataSource (); instance.setUrl (dataSourceDefinition.url ()); instance.setDriverClassName (dataSourceDefinition.className ()); visszatérési példány;}); }

Mint láthatjuk, szükségünk van a DataSourceDefinition amely biztosítja a DataSource tulajdonságokat.

Bármely kezelt babot a következő felirattal jelölhetjük:

@DataSourceDefinition (név = "ds", osztálynév = "org.h2.Driver", url = "jdbc: h2: mem: testdb")

Ezen tulajdonságok kinyerése érdekében megfigyeljük a ProcessAnnotatedType esemény a @Annotációkkal kommentár:

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

És végül meghallgatjuk a AfterDeployementValidation esemény, hogy megszerezzék a keresett személyeket Repülőút babot a CDI konténerből, majd hívja meg a vándorol() módszer:

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

7. Következtetés

A CDI hordozható kiterjesztés felépítése elsőre nehézkesnek tűnik, de miután megértettük a tároló inicializálási életciklusát és a kiterjesztéseknek szentelt SPI-t, ez egy nagyon hatékony eszközzé válik, amelyet felhasználhatunk keretrendszerek felépítésére a Jakarta EE tetején.

Szokás szerint a cikkben bemutatott összes kódminta megtalálható a GitHubon.