CDI: Injektionen filtern nach Modulzugehörigkeit

In der vergangenen Woche habe ich in unseren Seminarräumen in Berlin ein Training Java EE Masterclass durchgeführt, worin neben JPA, EJB und JSF auch das Thema CDI behandelt wird. Mit den engagierten Teilnehmern entwickelte sich insbesondere am Kursende eine interessante Diskussion zu diversen weiterführenden Themen, u. a. darüber, ob es möglich sei, eine Bibliothek so aus CDI-Komponenten aufzubauen, dass diese innerhalb der Bibliothek beliebig zur Injektion bereit gestellt werden, eine die Bibliothek nutzende Anwendung jedoch nur bestimmte Beans daraus angeboten bekommt, also bspw. so:

  • Library cdi-injectfilter-lib
    • definiert einen Service GreetingService, der mit Hilfe eines weiteres Services PartOfDayService realisiert wird.
    • GreetingService und PartOfDayService sind CDI Beans, die mittels Injektion miteinander verknüpft werden.
  • Anwendung cdi-injectfilter-web
    • nutzt GreetingService aus cdi-injectfilter-lib mittels Injektion,
    • soll PartOfDayService nicht (mittels Injektion) nutzen.

Die spontane Idee, PartOfDayService durch Annotation mit @Vetoed (bzw. @Typed) aus dem (CDI-) Rennen zu nehmen, greift zu kurz, weil dann nicht nur die Injektion eines PartOfDayService in cdi-injectfilter-web verhindert wird, sondern die Nutzung von PartOfDayService als CDI Bean generell, also auch in cdi-injectfilter-lib, unterdrückt wird.

Gesucht ist also eine Möglichkeit, die Injektion einer CDI Bean in Abhängikeit vom Injektionsziel zu erlauben oder verwehren. Dies gelingt relativ einfach damit, dass die betreffende Bibliothek – im Beispiel cdi-injectfilter-lib – zu einer CDI Extension gemacht wird. Dann können mit Hilfe eines Observers für den Lifecycle Event, den der Container während des Anwendungsdeployments für eine Injektionsstelle feuert, unerwünschte Injektionen abgelehtn werden.

Die folgenden Schritte sind dafür nötig:

  • Bibliothek zu einer CDI Extension machen:
    • Klasse als Implementierung von javax.enterprise.inject.spi.Extension entwerfen und im Service Descriptor META-INF/services/javax.enterprise.inject.spi.Extension registrieren
      (⇒de.gedoplan.beantrial.cdi.injectfilter.lib.extension.InjectFilterExtension),
    • darin eine Observer-Methode für den Event ProcessInjectionPoint<T, X> vorsehen. Diese Methode wird vom Container während des initialen Scans für jeden erkannten Injektionspunkt aufgerufen. Am übergebenen Event-Objekt kann man erkennen, was wohin injiziert werden soll. Unerwünschte Kombinationen können durch Aufruf der Event-Methode addDefinitionError mit Schimpf und Schande belegt werden.
  • Zur Unterscheidung der nur innerhalb des Bibliotheksmoduls frei nutzbaren Beans von denen, die auch ausserhalb injizierbar sein sollen, empfiehlt sich die Einführung eines entsprechenden CDI Qualifiers
    (⇒de.gedoplan.beantrial.cdi.injectfilter.lib.LibraryService).
    Die Injektion innerhalb der Library geschieht dann (natürlich) ausschliesslich unter Nutzung dieses Qualifiers.
    In der o. a. Observer-Methode können die betroffenen Injektionsstellen anhand des Qualifiers erkannt werden und Injektionen in Ziele ausserhalb der Library abgelehnt werden.
  • Eine unerwünschte Injektion sollte nun mit einen Deployment-Fehler belegt sein
    (⇒de.gedoplan.beantrial.cdi.injectfilter.web.presentation.ServicePresenter).

Der gesamte Beispielcode mit den genannten Klassen (⇒ …) findet sich auf GitHub.

Es sei darauf hingewiesen, dass die geschilderte Lösung ein paar kleine Contras hat:

  1. Der Beispielcode macht die „Injektionserlaubnis“ am Paket der Zielklasse fest. Das setzt eine „gutmütige“ Paketstruktur voraus. Würde ein(e) „kreative(r)“ Entwickler(in) der nutzenden Anwendung die Beans in Paketen platzieren, deren Name mit denen der genutzten Bibliothek übereinstimmen, würde er/sie die Injektionseinschränkung damit umgehen.
  2. Ebenfalls umgehen ließe sich die Injektionseinschränkung durch die Bereitstellung eines passenden Producers in der aufrufenden Anwendung.
  3. Die Einschränkung wird erst zum Deployent-Zeitpunkt erkennbar. Eine IDE wie Eclipse oder NetBeans wird vorher nicht warnen, wenn eine unerwünschte Injektion programmiert wird.

Die ersten beiden Nachteile treten bei „gutmütiger“ Softwareentwicklung nicht auf. Oder anders gesagt: Denen mit zuviel kreativer Energie kann so nicht geholfen werden. Der dritte Nachteil wird durch die empfohlene Nutzung eines Qualifiers zumindest weitgehend entschärft – soweit der Quallifier nicht kreativ misbraucht wird – aber das hatten wir ja schon.

Viel Spass/Erfolg mit komponentenbasierter Softwareentwicklung auf Basis von Java EE!

Zur Vertiefung sei auf unser umfangreiches Seminarangebot hingewiesen: GEDOPLAN IT Training. Alle Kurse gibt es auch kundenspezifisch angepasst!

Advertisements

Über Dirk Weil
Dirk Weil ist seit 1998 als Berater im Bereich Java tätig. Als Geschäftsführer der GEDOPLAN GmbH in Bielefeld ist er für die Konzeption und Realisierung von Informationssystemen auf Basis von Java EE verantwortlich. Seine langjährige Erfahrung in der Entwicklung anspruchsvoller Unternehmenslösungen machen ihn zu einem kompetenten Ansprechpartner und anerkannten Experten auf dem Gebiet Java EE. Er ist Autor in Fachmagazinen, hält Vorträge und leitet Seminare und Workshops aus einem eigenen Java-Curriculum.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: