Sven Ruppert Xuccess Reply GmbH

Manchmal kann man mit kleinen Implementierungen große Erfolge erzielen.

In den letzten Teilen der Artikelserie haben wir uns recht viel mit allen möglichen Arten von Proxys auseinandergesetzt und gezeigt, wie man all die dafür notwendigen Dinge programmieren kann. Aber wie so oft stellt sich nun die Frage, wie man das in sein Projekt einbinden kann.

Wir haben uns in den letzten Teilen dieser Serie mit den Proxys auseinandergesetzt. Begonnen hatten wir damit, Proxys manuell zu erstellen. Wir haben dabei gesehen, dass man diese auf Basis von Dynamic Proxys recht schnell realisieren kann. Später sind wir einen Schritt weiter gegangen und haben nicht ganze Instanzen maskiert, sondern nur noch einzelne Methoden. Das dazugehörige Pattern hieß DynamicObjectAdapter. Alles zusammen hat sich jedoch zu recht viel manueller Tätigkeit summiert, was dazu führte, dass wir uns das gute alte Annotation Processing angesehen haben, um so viel wie möglich zu generieren. Jetzt haben wir einen Haufen Proxys.

    Artikelserie

  • Teil 1: Das Builder-Pattern im Einsatz
  • Teil 2: Das Proxy-Pattern im Einsatz
  • Teil 3: Das DynamicObjectAdapter-Pattern im Einsatz
  • Teil 4: Typesafe DynamicObjectAdapter
  • Teil 5: Dependency-Injection-Frameworks

Wenn man sich nun in einer realen Umgebung mit den Proxys beschäftigt, kommt man natürlich zu den Stellen, an denen die Proxys erstellt werden. Hier ein Beispiel aus einem der ersten Artikel mit der Verwendung des ProxyBuilder.

final InnerDemoClass original = new InnerDemoClass();

final InnerDemoInterface demoLogic = ProxyBuilder
  .newDynamicProxyBuilder(InnerDemoInterface.class, original)
  .addSecurityRule(() -> true)
  .addSecurityRule(() -> true)
  .addMetrics()
  .build();

Der Quelltext, um Proxys zu erstellen, ist recht kompakt, hat aber im Businesscode eigentlich nichts verloren. Daraus ergeben sich verschiedene Fragen, aber schauen wir erst einmal im Detail hin. Hier wird ein Proxy erzeugt, was direkt zu der offensichtlichen Frage führt: Wann wird überhaupt ein Proxy benötigt? Ist die Stelle, an der ich ihn im Quelltext vorsehe, immer die richtige Wahl? Bei trivialen Beispielen ist das schon der Fall, aber leider nicht immer. Also erweitern wir das Beispiel um eine unsinnige, aber beispielhafte Endscheidung, ob jetzt der richtige Zeitpunkt für einen Proxy ist.

final InnerDemoClass original = new InnerDemoClass();

if(proxyNeeded) {
  final InnerDemoInterface demoLogic = ProxyBuilder
    .newDynamicProxyBuilder(InnerDemoInterface.class, original)
    .addSecurityRule(() -> true)
    .addSecurityRule(() -> true)
    .addMetrics()
    .build();
  return demoLogic;
} else {
  return original;
}

Und was ist mit der Komposition des Proxys selbst? Ist die Kombination aus SecurityProxy und MetricsProxy immer fix? Eine gute Frage. Extrahieren wir erst einmal das Erzeugen in eine eigene Methode mit dem Namen createInstance(..) und sehen uns die Verwendung an.

final boolean proxyNeeded = true; // dummy
  final boolean metricsNeeded = true; // dummy
  final boolean securityNeeded = true; // dummy

  final InnerDemoInterface instance = createInstance(
    new InnerDemoClass(),
    proxyNeeded,
    metricsNeeded,
    securityNeeded);

  final String hello = instance.workOn();
  System.out.println("hello = " + hello);
}

Was sofort auffällt, ist die Menge an Attributen, die benötigt wird; in diesem Fall drei Boolean-Werte und die Originalinstanz. Hier haben wir uns noch nicht überlegt, wie die Entscheidung für den jeweiligen Boolean-Wert getroffen worden ist und nehmen die Dummy-Werte an. Die Methode createInstance(..) selbst muss nun alle Fälle abfangen. Wenn nachträglich eine weitere Proxy-Art hinzukommt, kann man sich vorstellen, zu was das führen wird. In Listing 4 ist eine mögliche Lösung zu sehen, die recht schnell zeigt, dass man sie nicht öfter in einem echten Projekt sehen möchte. Da muss es doch eine generische Lösung geben!

private InnerDemoInterface createInstance(final InnerDemoClass original,
                                          final boolean proxyNeeded,
                                          final boolean securityNeeded,
                                          final boolean metricsNeeded) {
    if (proxyNeeded) {

      DynamicProxyBuilder<InnerDemoInterface, InnerDemoClass>
      proxyBuilder = ProxyBuilder
        .newDynamicProxyBuilder(InnerDemoInterface.class, original);

      proxyBuilder
        = ((securityNeeded) ?
          proxyBuilder
            .addSecurityRule(() -> true)
            .addSecurityRule(() -> true)
          : proxyBuilder);

      proxyBuilder 
        = ((metricsNeeded) ? proxyBuilder.addMetrics() : proxyBuilder);

      return proxyBuilder.build();
    } else {
      return original;
    }
  }

Am besten ist es, wenn der direkte Methodenaufruf zur Erzeugung der Instanz komplett entfällt. Schön wäre es, wenn man nur noch definiert, dass eine Instanz benötigt wird. In den Businessquelltexten möchte man doch keine technischen Details erkennen.

Den vollständigen Artikel lesen Sie in der Ausgabe:

Java Magazin 1.17 - "Ich habe fertig!"

Alle Infos zum Heft
579750559Praktischer Einsatz von Proxys mit Dependency-Injection-Frameworks
X
- Gib Deinen Standort ein -
- or -