Ich versuche herauszufinden, welche Optionen ich für die Architektur meines API-Projekts habe.
Ich möchte eine API mit JAX-RS Version 1.0 erstellen. Diese API verbraucht Remote EJBs (EJB 3.0) von einer größeren, alten und komplexen Anwendung. Ich benutze Java 6.
Bisher kann ich das machen und arbeite. Aber ich bin nicht mit der Lösung zufrieden. Siehe meine Paketdisposition. Meine Bedenken sind nach dem Code beschrieben:
%Vor% Beispiel für com.organization.api.v1.rs.UserV1RS
:
Beispiel für com.organization.api.v1.services.UserV1Service
:
Beispiel für com.organization.api.services.UserService
:
Einige Anforderungen meines Projekts:
UserV1Service
und UserV2Service
mit UserService
. UserV1Service
und OrderV2Service
mit AnotherService
. UserV1VO
und nicht UserVO
). Was mich an dem obigen Code kaputt macht:
ServiceLocator
Klasse ist für mich kein guter Ansatz. Diese Klasse verwendet Legacy-Code aus einer alten Bibliothek und ich habe viele Fragen darüber, wie diese Klasse funktioniert. Die Art und Weise, wie ich ServiceLocator
verwenden kann, ist auch für mich sehr merkwürdig und diese Strategie ist nicht gut, um das zu verspotten Dienstleistungen für meine Unit Tests . Ich möchte einen neuen ServiceLocator erstellen oder eine Abhängigkeitsinjektionsstrategie (oder einen anderen besseren Ansatz) verwenden. UserService
soll nicht von einem anderen "externen" Dienst wie OrderService
verwendet werden. Es ist nur für die UserVxService
. Aber vielleicht möchte OrderService
in der Zukunft Code aus UserService
... ServiceLocator
eine Menge lookups
unter meinem Code machen. Die Möglichkeit, eine zyklische Abhängigkeit zu erzeugen (serviceOne-NachschlagedienstZwei dieser NachschlagedienstDreier NachschlagedienstOne) ist sehr hoch. UserV1VO
in meinen nicht versionierten Diensten ( com.organization.api.services
) verwendet werden, aber das kann nicht passieren. Eine gute Architektur lässt etwas nicht zu, was nicht erlaubt ist. Ich habe die Idee, ein neues Projekt zu erstellen, wie zum Beispiel api-services
und das com.organization.api.services
, um dies zu vermeiden. Ist das eine gute Lösung? Also ... Ideen?
Ein paar Dinge, die ich sehe:
Das UserService
sollte idealerweise auf einer Schnittstelle basieren. Sie scheinen einen ähnlichen Vertrag zu haben, aber der einzige Unterschied sind ihre Quellen (RemoteEJB, LocalServiceLocator). Diese sollten DTOs zurückgeben
UserV1Service extends UserService
sollte keine Vererbung verwenden, sondern stattdessen die Komposition bevorzugen. Denken Sie darüber nach, was Sie für v2 des gleichen Dienstes tun müssten. Basierend auf Ihrem Beispiel erhalten Sie UserV2Service extends UserService
. Dies ist insbesondere dann nicht ideal, wenn Sie in Ihrer Basisklasse abstrakte Methoden erhalten, die für eine bestimmte Version spezifisch sind. Dann müssen plötzlich andere versionierte Dienste dafür sorgen.
Für den ServiceLocator
Es ist besser, wenn Sie in Ihrem Fall ein Framework zur Abhängigkeitsinjektion wie Spring oder vielleicht CDI verwenden. Dies würde nur für Ihren eigenen Code gelten, wenn Ihr Projekt neu ist.
Für diejenigen, die schwer zu testen sind, würden Sie die RemoteEJB-Aufrufe in eine eigene Oberfläche umbrechen, die das Nachstellen erleichtert. Die Tests für RemoteEJBs wären dann Integrationstests für dieses Projekt.
Die UserService-Klasse soll nicht von einem anderen "externen" Dienst wie OrderService verwendet werden. Es ist nur für den UserVxService. Aber vielleicht möchte OrderService in der Zukunft Code von UserService verwenden
Es ist nichts falsch daran, dass Dienste auf derselben Ebene miteinander kommunizieren.
Bei diesem Ansatz könnten die VOs, wie UserV1VO, in meinem verwendet werden nicht versionierte Dienste (com.organization.api.services), aber dies kann nicht geschehen. Eine gute Architektur lässt etwas nicht zu, was nicht erlaubt ist. Ich habe die Idee, ein neues Projekt wie api-services zu kreieren und die com.organization.api.services dort, um dies zu vermeiden. Ist das gut? Lösung?
Nur weil du etwas tun kannst, heißt das nicht, dass du es tun solltest. Es scheint zwar eine gute Idee zu sein, die Ebene in ein eigenes Projekt zu unterteilen. In der Realität hält ein Entwickler nichts davon ab, entweder dieselbe Klasse in diesem Projekt neu zu erstellen oder das jar in den Klassenpfad aufzunehmen und dieselbe Klasse zu verwenden. Ich sage nicht, dass es falsch ist, sie zu spalten, nur dass sie aus den richtigen Gründen gespalten werden sollte, anstatt "Was-wäre-wenn-Szenarien".
Ich habe diese Lösung (Danke @ Shiraaz.M):
Ich entferne alle Erweiterungen in meinen Diensten und lösche die gefährliche ServiceLocator-Klasse. Diese Erbschaften ohne einen guten Zweck und Service Locator sind beide schlechte Ideen. Ich versuche Guice zu verwenden, um die Abhängigkeiten in meine REST-Ressourcen zu injizieren, aber das ist nicht so einfach in meiner Jax-rs Version. Aber meine Dienste sind sehr einfach und einfach zu erstellen, so dass meine Lösung einfach war:
%Vor%Und mein UserV1Service:
%Vor%Mit dieser Strategie ist es einfach, andere Dienste mit Komposition zu verwenden.
Tags und Links java jax-rs architecture ejb-3.0 api-versioning