Design Pattern – Dependency Injection

Zur Freude von vielen Entwicklern setzt Magnolia ab Version 4.5 auf das Dependency Injection Design-Pattern (oder Inversion of Control). Dieses Pattern gibt es jetzt schon eine ganze Weile und hat sich spätestens mit dem Spring Framework für Java bei vielen Projekten bewährt.

In einem klassischen objektorientierten System (ohne Dependency Injection) ist jedes Objekt selbst dafür zuständig, seine Abhängigkeiten, also benötigte Objekte und Resourcen, zu erzeugen und zu verwalten. Mit Dependeny Injection kann die Verantwortung für das Erzeugen und Verknüpfen von Objekten an eine zentrale, eigenständige Komponente bzw. Framework, übertragen werden.

Vorteile

Dependency Injection erleichtert die Entkopplung der Systemkomponenten. Sind die Komponenten loser gekoppelt führt das zu einer verbesserten Testbarkeit. Weitere Vorteile sind u.a. die Steigerung der Code Lesbarkeit bzw. Verständlichkeit und eine gesteigerte Qualität durch die Verringerung der Komplexität.

Framework

Bekannte und auch bewährte Frameworks mit Dependency Injection Unterstützung sind u.a. Spring, Google Guice und PicoContainer. Magnolia hat sich gegen Spring mit einem grossen Ökosystem und für Google Guice als reinen Inversion of Control Container entschieden. Wer dennoch nicht auf Spring und dessen Bibliotheken in Magnolia verzichten will, dem sei Magnolia Blossom als Spring Integration ans Herz gelegt.

Beispiel

In diesem Beispiel wird für das Model einer Magnolia Komponente die eigentliche Implementation des GeoService erst zur Laufzeit (vom Guice Framework) bestimmt und enstprechend injiziert bzw. injected. Im Model selbst wird ausschliesslich gegenüber dem Interface (dem Typ) GeoService entwickelt.

Es muss die @Inject (javax.inject.Inject) Annotation vorhanden sein, wie in diesem Beispiel auf dem Konstruktor der Klasse (Constructor Injection).

public class SomeGeoAwareModel extends RenderingModelImpl
{
    private final GeoService geoService;

    @Inject
    public SomeGeoAwareModel(GeoService geoService)
    {
        this.geoService = geoService;
    }

    public String execute() {
        ...
    }
}

Die eigentliche Implementation eines Typs kann im Magnolia Modul-Descriptor XML konfiguriert werden. In diesem Beispiel wird eine Komponente vom Typ GeoService (ein Interface) definiert. Die eigentlich Implementation ist die GeoServiceImpl.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module SYSTEM "module.dtd">
<module>
  <name>my-module</name>
  <version>1.0</version>
  <components>
    <id>main</id> <!-- Container ID -->
    <component>
      <type>com.acme.geo.GeoService</type>
      <implementation>com.acme.geo.GeoServiceImpl</implementation>
    </component>
  </components>
</module>

Über die Container ID kann die Startup-Phase (bzw. der Component-Provider der entsprechenden Phase) der Komponenten bestimmt werden. Für die meisten Fälle wird main als Container ID Sinn machen. Weitere IDs können der Darstellung der Component-Provider Hierarchie auf dieser Seite entnommen werden.

Unterstützte Depencency Injection Typen

Im obigen Beispiel wurde die Abhängigkeit über den Konstruktor injected (Contructor Injection) definiert. Die Annotation kann aber auch auf Setter-Methode (Setter Injection) angewendet werden. Ausserdem auch auf Felder (Field Injection), jedoch sollte das aus Gründen der Testbarkeit vermieden werden. Eine Ausnahme dafür sind Properties, wie im Beispiel für magnolia.develop.

public class SomeGeoAwareModel extends RenderingModelImpl
{
    private RemoteService remoteService;

    @Inject
    @Named("magnolia.develop")
    private Provider<String> developmentMode;

    @Inject
    public void setRemoteService(RemoteService remoteService)
    {
        this.remoteService = remoteService;
    }
}

In seltenen Fällen ist es nötig als Alternative zur Dependency Injection die Instanzen von der statischen Utility-Klasse info.magnolia.objectfactory.Components zu beziehen. Neue Instanzen können mittels der Methode

Components.newInstance(Class<T> type, Object... parameters)

und Singleton’s mit der Methode

Components.getComponent(Class<T> type)

bezogen werden.

Feature Set

Magnolia mit Guice Integration unterstüzt neben der @Inject Annotation noch weitere standardisierte JSR-330 Annotation, die auf dieser Seite gelistet sind.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>