
Hallo Habr!
Dieses Buch beschreibt die neue Generation von Java EE. Sie begeben sich auf eine Reise durch Java EE im Kontext der modernen Welt der Mikrodienste und Container. Dies ist eher kein Referenzhandbuch für die API-Syntax. Die hier vorgestellten Konzepte und Techniken spiegeln die tatsächlichen Erfahrungen einer Person wider, die diesen Weg kürzlich gegangen ist, dabei auf auftretende Hindernisse achtet und bereit ist, ihr Wissen weiterzugeben. In einer Vielzahl von Situationen, von der Erstellung eines Pakets zum Testen und zur Verwendung in der Cloud, ist dieses Buch ein idealer Begleiter für Anfänger und erfahrene Entwickler, die mehr als nur eine API verstehen und ihnen dabei helfen möchten, ihr Denken neu zu erstellen, um eine moderne Anwendungsarchitektur in Java EE zu erstellen .
Ausführungssequenz
In Unternehmensanwendungen implementierte Geschäftsprozesse beschreiben bestimmte Prozessabläufe. Bei den beteiligten Geschäftsszenarien handelt es sich entweder um einen synchronen Anforderungs- und Antwortprozess oder um eine asynchrone Verarbeitung eines initiierten Prozesses.
Geschäftsszenarien werden in separaten Threads aufgerufen, einem Thread pro Anforderung oder Aufruf. Streams werden vom Container erstellt und zur Wiederverwendung in das Laufwerk gestellt, nachdem der Anruf erfolgreich verarbeitet wurde. Standardmäßig werden in Anwendungsklassen definierte Geschäftsprozesse sowie Querschnittsaufgaben wie Transaktionen nacheinander ausgeführt.
Synchrone Ausführung
Ein typisches Szenario, in dem eine HTTP-Anforderung eine Antwort von der Datenbank erfordert, wird wie folgt implementiert. Ein Thread verarbeitet die in der Schleife ankommende Anforderung, beispielsweise die JAX-RS UsersResource, indem er das Steuerprinzip invertiert. Die JAX-RS-Ressourcenmethode wird vom Container aufgerufen. Die Ressource implementiert und verwendet das UserManagement EJB, das auch implizit vom Container aufgerufen wird. Alle Operationen werden von Vermittlern synchron ausgeführt. Der Benutzer-EJB verwendet den Entitätsmanager zum Speichern der neuen Entität. Sobald die Geschäftsmethode, die die aktuell aktive Transaktion initiiert hat, abgeschlossen ist, versucht der Container, die Transaktion in die Datenbank zu übertragen. Abhängig vom Ergebnis der Transaktion nimmt die Ressourcenmethode der Schaltung den Betrieb wieder auf und generiert eine Antwort an den Client. Alles geschieht synchron, zu diesem Zeitpunkt ist der Client blockiert und wartet auf eine Antwort.
Die synchrone Ausführung umfasst die Verarbeitung synchroner CDI-Ereignisse. Sie trennen das Auslösen von Domänenereignissen von ihrer Verarbeitung, Ereignisse werden jedoch synchron verarbeitet. Es gibt verschiedene Methoden zur Überwachung von Transaktionen. Wenn eine Transaktionsphase angezeigt wird, kann das Ereignis in dieser Phase verarbeitet werden - während der Transaktionsfixierung, vor deren Abschluss, nach Abschluss, falls eine Transaktion nicht erfolgreich oder erfolgreich ist. Standardmäßig oder wenn die Transaktion inaktiv ist, werden CDI-Ereignisse sofort verarbeitet, wenn sie auftreten. Auf diese Weise können Ingenieure komplexe Lösungen implementieren, z. B. mithilfe von Ereignissen, die erst nach erfolgreichem Hinzufügen von Entitäten zur Datenbank auftreten. Wie auch immer, die Verarbeitung erfolgt in jedem Fall synchron.
Asynchrone Ausführung
Die synchronisierte Ausführung von Aufgaben erfüllt die Anforderungen vieler Geschäftsszenarien, aber manchmal benötigen Sie asynchrones Verhalten. Es gibt eine Reihe von Einschränkungen für die Verwendung von Threads in der Java EE-Umgebung. Der Container verwaltet Ressourcen und Flüsse und legt sie im Laufwerk ab. Externe Dienstprogramme zur Parallelitätskontrolle befinden sich außerhalb des Containers und kennen diese Streams nicht. Daher sollte der Anwendungscode seine Threads nicht ausführen und steuern. Zu diesem Zweck werden die Java EE-Funktionen verwendet. Es gibt mehrere APIs mit integrierter asynchroner Unterstützung.
Asynchrone EJB-MethodenDer einfachste Weg, asynchrones Verhalten zu implementieren, besteht darin, die Annotation @Asynchronous für eine Geschäftsmethode der EJB- oder EJB-Klasse zu verwenden. Aufrufe dieser Methoden werden sofort zurückgegeben, manchmal mit einer Antwort vom Typ Future. Sie laufen in einem separaten Thread, der vom Container gesteuert wird. Diese Methode eignet sich gut für einfache Szenarien, ist jedoch auf EJBs beschränkt:
@Asynchronous @Stateless public class Calculator { public void calculatePi(long decimalPlaces) {
Leistungsmanagement-ServiceFür die asynchrone Ausführung von Aufgaben in verwalteten CDI-Objekten oder mithilfe von Java SE-Dienstprogrammen zur Parallelitätskontrolle enthält Java EE containerverwaltete Versionen der Funktionen ExecutorService und ScheduledExecutorService. Sie werden verwendet, um asynchrone Aufgaben in containergesteuerten Threads zu implementieren. Die Instanzen ManagedExecutorService und ManagedScheduledExecutorService sind in den Anwendungscode eingebettet. Sie können verwendet werden, um ihre eigene Logik auszuführen, sind jedoch am effektivsten, wenn sie mit Java SE-Dienstprogrammen zur Parallelitätskontrolle kombiniert werden, z. B. mit ergänzten zukünftigen Werten. Das folgende Beispiel zeigt, wie aufgefüllte zukünftige Werte mithilfe von containergesteuerten Threads erstellt werden:
import javax.annotation.Resource; import javax.enterprise.concurrent.ManagedExecutorService; import java.util.Random; import java.util.concurrent.CompletableFuture; @Stateless public class Calculator { @Resource ManagedExecutorService mes; public CompletableFuture<Double> calculateRandomPi(int maxDecimalPlaces) { return CompletableFuture.supplyAsync(() -> new Random().nextInt(maxDecimalPlaces) + 1, mes) .thenApply(this::calculatePi); } private double calculatePi(long decimalPlaces) { … } }
Das Calculator-Objekt gibt den ergänzten zukünftigen Wert des Doppeltyps zurück, der noch berechnet werden kann, wenn der aufrufende Kontext fortgesetzt wird. Es kann angefordert werden, wenn die Berechnungen abgeschlossen sind, und mit nachfolgenden Berechnungen kombiniert werden. Unabhängig davon, wo neue Threads in der Unternehmensanwendung erforderlich sind, sollten Sie die Java EE-Funktionalität verwenden, um sie zu verwalten.
Asynchrone CDI-EreignisseCDI-Ereignisse können auch asynchron verarbeitet werden. In diesem Fall stellt der Container auch einen Stream zum Behandeln von Ereignissen bereit. Um einen asynchronen Ereignishandler zu beschreiben, wird die Methode mit @ObservesAsync kommentiert und das Ereignis mit der fireAsync () -Methode aktiviert. Die folgenden Codefragmente veranschaulichen asynchrone CDI-Ereignisse:
@Stateless public class CarManufacturer { @Inject CarFactory carFactory; @Inject Event<CarCreated> carCreated; public Car manufactureCar(Specification spec) { Car car = carFactory.createCar(spec); carCreated.fireAsync(new CarCreated(spec)); return car; } }
Der Ereignishandler wird in einem eigenen Container-verwalteten Thread aufgerufen:
import javax.enterprise.event.ObservesAsync; public class CreatedCarListener { public void onCarCreated(@ObservesAsync CarCreated event) {
Aus Gründen der Abwärtskompatibilität können synchrone CDI-Ereignisse auch in der asynchronen EJB-Methode verarbeitet werden. Daher werden Ereignisse und Handler als synchron definiert, und die Handlermethode ist eine EJB-Geschäftsmethode mit @ Asynchronous-Annotation. Bevor asynchrone Ereignisse in den CDI-Standard für Java EE 8 eingeführt wurden, war dies die einzige Möglichkeit, diese Funktion zu implementieren. Um Verwirrung in Java EE 8 und höher zu vermeiden, wird diese Implementierung am besten vermieden.
Asynchrone VerarbeitungsbereicheDa der Container keine Informationen darüber enthält, wie lange asynchrone Aufgaben ausgeführt werden können, ist die Verwendung von Bereichen in diesem Fall begrenzt. Objekte mit einem Bereich innerhalb der Anforderung oder Sitzung, die zum Zeitpunkt des Starts der asynchronen Aufgabe verfügbar waren, sind während der gesamten Implementierung nicht unbedingt aktiv. Die Anforderung und die Sitzung werden möglicherweise lange vor ihrem Abschluss beendet. Daher haben Threads, die asynchrone Aufgaben ausführen, z. B. die vom geplanten Executor-Dienst bereitgestellten oder asynchronen Ereignisse, möglicherweise keinen Zugriff auf verwaltete Entitätsinstanzen im Rahmen der Anforderung oder Sitzung, die während des Aufrufs aktiv waren. Gleiches gilt für den Zugriff auf Links zu eingebetteten Instanzen, beispielsweise in Lambda-Methoden, die Teil der synchronen Ausführung sind.
Dies muss bei der Modellierung asynchroner Aufgaben berücksichtigt werden. Alle Informationen zu einem bestimmten Anruf sollten zum Zeitpunkt des Starts der Aufgabe bereitgestellt werden. Eine asynchrone Aufgabe kann jedoch eigene Instanzen verwalteter Objekte mit einem begrenzten Bereich haben.
Zeitausführung einstellenGeschäftsszenarien können nicht nur von außen aufgerufen werden, beispielsweise über eine HTTP-Anforderung, sondern auch von innerhalb der Anwendung - eine Aufgabe, die zu einem bestimmten Zeitpunkt ausgeführt wird.
In der Unix-Welt ist die Funktionalität zum Ausführen von periodischen Jobs beliebt - dies sind die Aufgaben des Schedulers. EJBs bieten ähnliche Funktionen mit EJB-Timern. Timer rufen Geschäftsmethoden in bestimmten Intervallen oder nach einer bestimmten Zeit auf. Das folgende Beispiel beschreibt einen zyklischen Timer, der alle zehn Minuten startet:
import javax.ejb.Schedule; import javax.ejb.Startup; @Singleton @Startup public class PeriodicJob { @Schedule(minute = "*/10", hour = "*", persistent = false) public void executeJob() {
Alle EJBs - Singletones, verwaltete Objekte mit oder ohne Statuspersistenz - können Timer erstellen. In den meisten Szenarien ist es jedoch sinnvoll, Timer nur für Singleton zu erstellen. Die Verzögerung wird für alle aktiven Objekte eingestellt. Normalerweise ist es erforderlich, geplante Aufgaben rechtzeitig zu starten, weshalb es in Singleton verwendet wird. Aus dem gleichen Grund muss in diesem Beispiel das EJB-Objekt beim Start der Anwendung aktiv sein. Dies stellt sicher, dass der Timer sofort funktioniert.
Wenn Sie den Timer als Konstante beschreiben, erstreckt sich seine Lebensdauer auf den gesamten Lebenszyklus der JVM. Der Container ist für das Speichern persistenter Timer verantwortlich, normalerweise in der Datenbank. Permanente Timer, die funktionieren sollten, während die Anwendung nicht verfügbar ist, werden beim Start aktiviert. Außerdem können Sie dieselben Timer mit mehreren Instanzen des Objekts verwenden. Konstante Timer mit einer geeigneten Serverkonfiguration sind eine geeignete Lösung, wenn Sie einen Geschäftsprozess genau einmal auf mehreren Servern ausführen müssen.
Timer, die mithilfe der
Schedule- Annotation automatisch erstellt werden, werden mit Unix-ähnlichen Cron-Ausdrücken beschrieben. Für zusätzliche Flexibilität werden EJB-Timer programmgesteuert mithilfe des vom Container bereitgestellten Timer-Dienstes beschrieben, der die Rückrufmethoden Timer und
Timeout erstellt .
Periodische und zurückgestellte Aufgaben können auch außerhalb der EJBs mithilfe des Container-verwalteten Scheduler-Dienstes beschrieben werden. In den verwalteten Komponenten ist eine Instanz von ManagedScheduledExecutorService implementiert, die Aufgaben nach der angegebenen Verzögerung oder in festgelegten Intervallen ausführt. Diese Aufgaben werden in containergesteuerten Threads implementiert:
@ApplicationScoped public class Periodic { @Resource ManagedScheduledExecutorService mses; public void startAsyncJobs() { mses.schedule(this::execute, 10, TimeUnit.SECONDS); mses.scheduleAtFixedRate(this::execute, 60, 10, TimeUnit.SECONDS); } private void execute() { … } }
Durch Aufrufen der Methode startAsyncJobs () wird die Funktion execute () für den verwalteten Thread zehn Sekunden nach dem Aufruf und dann alle zehn Sekunden nach der ersten Minute ausgeführt.
Asynchronität und Reaktivität in JAX-RSJAX-RS unterstützt asynchrones Verhalten, um serverseitige Anforderungsflüsse nicht unnötig zu blockieren. Selbst wenn eine HTTP-Verbindung auf eine Antwort wartet, verarbeitet der Anforderungsdatenstrom möglicherweise weiterhin andere Anforderungen, während ein langer Prozess auf dem Server ausgeführt wird. Anforderungsflüsse werden in einem Container zusammengefasst, und dieses Anforderungsrepository hat eine bestimmte Größe. Um den Anforderungsdatenstrom nicht zu verschwenden, erstellen die asynchronen JAX-RS-Ressourcenmethoden Aufgaben, die ausgeführt werden, wenn der Anforderungsdatenstrom zurückkehrt und wiederverwendet werden kann. Die HTTP-Verbindung wird fortgesetzt und gibt nach Abschluss der asynchronen Task oder nach einer Zeitüberschreitung eine Antwort. Das folgende Beispiel zeigt die asynchrone Ressourcenmethode JAX-RS:
@Path("users") @Consumes(MediaType.APPLICATION_JSON) public class UsersResource { @Resource ManagedExecutorService mes; … @POST public CompletionStage<Response> createUserAsync(User user) { return CompletableFuture.supplyAsync(() -> createUser(user), mes); } private Response createUser(User user) { userStore.create(user); return Response.accepted().build(); } }
Um den Anforderungsfluss zu lange beschäftigt zu halten, muss die JAX-RS-Methode schnell abgeschlossen werden. Dies liegt daran, dass die Ressourcenmethode mittels Steuerungsinversion aus dem Container aufgerufen wird. Das in der Abschlussphase erhaltene Ergebnis wird verwendet, um die Clientverbindung am Ende der Verarbeitung wieder aufzunehmen.
Die Rückkehr der Abschlussphasen ist eine relativ neue Technologie in der JAX-RS-API. Wenn Sie die Verzögerung beschreiben und gleichzeitig eine größere Flexibilität bei einer asynchronen Antwort bieten müssen, können Sie den Typ AsyncResponse in die Methode aufnehmen. Dieser Ansatz wird im folgenden Beispiel demonstriert:
import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; @Path("users") @Consumes(MediaType.APPLICATION_JSON) public class UsersResource { @Resource ManagedExecutorService mes; … @POST public void createUserAsync(User user, @Suspended AsyncResponse response) { response.setTimeout(5, TimeUnit.SECONDS); response.setTimeoutHandler(r -> r.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).build())); mes.execute(() -> response.resume(createUser(user))); } }
Dank der erstellten Zeitüberschreitungen wartet die Clientanforderung nicht unbegrenzt, sondern nur bis das Ergebnis eingeht oder das Anrufzeitlimit abläuft. Die Berechnungen werden jedoch fortgesetzt, da sie asynchron ausgeführt werden. Für JAX-RS-Ressourcen, die als EJBs implementiert sind, können Sie die Annotation @Asynchronous anwenden, damit Sie asynchrone Geschäftsmethoden nicht explizit über den Service Executor aufrufen.
Der JAX-RS-Client unterstützt auch asynchrones Verhalten. Abhängig von den Anforderungen ist es sinnvoll, es bei HTTP-Aufrufen nicht zu blockieren. Das vorherige Beispiel zeigt, wie Verzögerungen für Clientanforderungen festgelegt werden. Für lang laufende und insbesondere parallele externe Systemaufrufe ist es besser, asynchrones und reaktives Verhalten zu verwenden.
Betrachten Sie mehrere Serveranwendungen, die Wetterinformationen bereitstellen. Die Client-Komponente greift auf alle diese Anwendungen zu und berechnet die durchschnittliche Wettervorhersage. Im Idealfall können Sie parallel auf Systeme zugreifen:
import java.util.stream.Collectors; @ApplicationScoped public class WeatherForecast { private Client client; private List<WebTarget> targets; @Resource ManagedExecutorService mes; @PostConstruct private void initClient() { client = ClientBuilder.newClient(); targets = … } public Forecast getAverageForecast() { return invokeTargetsAsync() .stream() .map(CompletableFuture::join) .reduce(this::calculateAverage) .orElseThrow(() -> new IllegalStateException(" ")); } private List<CompletableFuture<Forecast>> invokeTargetsAsync() { return targets.stream() .map(t -> CompletableFuture.supplyAsync(() -> t .request(MediaType.APPLICATION_JSON_TYPE) .get(Forecast.class), mes)) .collect(Collectors.toList()); } private Forecast calculateAverage(Forecast first, Forecast second) { … } @PreDestroy public void closeClient() { client.close(); } }
Die Methode invokeTargetsAsync () ruft verfügbare Objekte asynchron auf und ruft den geplanten Executor-Service auf. CompletableFuture-Deskriptoren werden zurückgegeben und zur Berechnung der gemittelten Ergebnisse verwendet. Der Start der join () -Methode wird blockiert, bis der Aufruf abgeschlossen ist und die Ergebnisse empfangen werden.
Objekte, die asynchron aufgerufen werden, starten und warten auf eine Antwort von mehreren Ressourcen gleichzeitig, möglicherweise langsamer. In diesem Fall dauert das Warten auf Antworten von den Wetterdienstressourcen genauso lange wie das Erwarten der langsamsten Antwort und nicht aller Antworten zusammen.
Die neueste Version von JAX-RS bietet integrierte Unterstützung für Abschlussphasen, wodurch stereotyper Code in Anwendungen reduziert wird. Wie bei aufgefüllten Werten gibt der Aufruf sofort den Abschlussphasencode zur späteren Bezugnahme zurück. Das folgende Beispiel zeigt JAX-RS-reaktive Clientfunktionen mit dem Aufruf rx ():
public Forecast getAverageForecast() { return invokeTargetsAsync() .stream() .reduce((l, r) -> l.thenCombine(r, this::calculateAverage)) .map(s -> s.toCompletableFuture().join()) .orElseThrow(() -> new IllegalStateException(" ")); } private List<CompletionStage<Forecast>> invokeTargetsAsync() { return targets.stream() .map(t -> t .request(MediaType.APPLICATION_JSON_TYPE) .rx() .get(Forecast.class)) .collect(Collectors.toList()); }
Im obigen Beispiel müssen Sie nicht nach dem Dienst der geplanten Ausführenden suchen - der JAX-RS-Client verwaltet dies selbst. Bevor die Methode rx () angezeigt wurde, verwendeten die Clients einen expliziten Aufruf von async (). Diese Methode verhielt sich ähnlich, gab jedoch nur zukünftige Objekte zurück. Die Verwendung eines reaktiven Ansatzes bei Kunden ist für die meisten Projekte optimal.
Wie Sie sehen können, verwendet Java EE einen Container-verwalteten Künstlerdienst.
Designkonzepte und -prinzipien in modernem Java EE
Die Java EE-API basiert auf Konventionen und Entwurfsprinzipien, die als Standards festgelegt sind. Softwareentwickler finden darin bekannte API-Vorlagen und Anwendungsentwicklungsansätze. Das Ziel von Java EE ist es, die konsistente Verwendung der API zu fördern.
Das Hauptprinzip von Anwendungen, die sich hauptsächlich auf die Implementierung von Geschäftsszenarien konzentrieren, lautet: Die Technologie sollte nicht stören. Wie bereits erwähnt, sollten sich Ingenieure auf die Implementierung von Geschäftslogik konzentrieren können, ohne die meiste Zeit mit Technologie- und Infrastrukturproblemen zu verbringen. Im Idealfall ist die Domänenlogik in einfachem Java implementiert und wird durch Anmerkungen und andere Eigenschaften ergänzt, die von der Unternehmensumgebung unterstützt werden, ohne den Domänencode zu beeinflussen oder zu komplizieren. Dies bedeutet, dass die Technologie nicht viel Aufmerksamkeit der Ingenieure erfordert und keine zu großen Einschränkungen auferlegt. Die J2EE-Umgebung erforderte früher viele sehr komplexe Lösungen. Um die Schnittstellen zu implementieren und die Basisklassen zu erweitern, mussten wir verwaltete Objekte und persistente Speicherobjekte verwenden. Dies komplizierte die Logik des Themenbereichs und erschwerte das Testen.
In Java EE wird die Domänenlogik in Form einfacher Java-Klassen implementiert, die mit Anmerkungen ausgestattet sind, nach denen der Container bestimmte Unternehmensaufgaben während der Ausführung der Anwendung löst. Bei der Erstellung von sauberem Code wird häufig Code geschrieben, der für die Wiederverwendung eher schön als praktisch ist. Java EE unterstützt diesen Ansatz. Wenn Sie aus irgendeinem Grund die Technologie entfernen und die reine Logik des Themenbereichs verlassen müssen, löschen Sie einfach die entsprechenden Anmerkungen.
Wie wir in Kapitel 7 sehen werden, erfordert dieser Programmieransatz das Testen, da für Programmierer die meisten Java EE-Spezifikationen nichts anderes als Anmerkungen sind.
In der gesamten API wurde ein Entwurfsprinzip namens Inversion of Control (IoC) übernommen - mit anderen Worten: "Rufen Sie uns nicht an, wir nennen uns selbst." Dies macht sich insbesondere in Anwendungsschaltungen wie JAX-RS-Ressourcen bemerkbar. Ressourcenmethoden werden mithilfe von Java-Methodenanmerkungen beschrieben, die später vom Container im entsprechenden Kontext aufgerufen werden. Gleiches gilt für die Abhängigkeitsinjektion, bei der Sie Generatoren auswählen oder Querschnittsaufgaben wie Abfangjäger berücksichtigen müssen. Anwendungsentwickler können sich auf die Implementierung von Logik und die Beschreibung von Beziehungen konzentrieren und die Implementierung technischer Details in einem Container belassen. Ein anderes Beispiel, das nicht so offensichtlich ist, ist die Beschreibung der Konvertierung von Java-Objekten in JSON und umgekehrt durch JSON-B-Annotationen. Objekte werden nicht nur in einer expliziten, programmierten Form, sondern auch implizit in einem deklarativen Stil transformiert.
Ein weiteres Prinzip, mit dem Ingenieure diese Technologie effektiv anwenden können, ist die vereinbarte Programmierung. Standardmäßig definiert Java EE ein bestimmtes Verhalten, das den meisten Verwendungsszenarien entspricht. Wenn es nicht ausreicht oder die Anforderungen nicht erfüllt, kann das Verhalten häufig auf mehreren Ebenen neu definiert werden.
Es gibt viele Beispiele für die Programmierung von Konventionen. Eine davon ist die Verwendung von JAX-RS-Ressourcenmethoden, die Java-Funktionen in HTTP-Antworten konvertieren. Wenn das Standardverhalten von JAX-RS in Bezug auf Antworten die Anforderungen nicht erfüllt, können Sie den Antworttyp Antwort anwenden. Ein weiteres Beispiel ist die Spezifikation verwalteter Objekte, die normalerweise mithilfe von Anmerkungen implementiert wird. Um dieses Verhalten zu ändern, können Sie den XML-Deskriptor beans.xml verwenden. Für Programmierer ist es sehr praktisch, dass in der modernen Java EE-Welt Unternehmensanwendungen auf eine pragmatische und leistungsstarke Weise entwickelt werden, die normalerweise keine so intensive Verwendung von XML wie zuvor erfordert.
Ein weiteres wichtiges Entwicklungsprinzip für Java EE ist die Produktivität von Programmierern, da diese Plattform die Integration verschiedener Standards in den Container erfordert. Da Container einen bestimmten Satz von APIs unterstützen - und wenn die gesamte Java EE-API unterstützt wird, ist dies genau der Fall -, sind auch API-Implementierungen erforderlich, um eine nahtlose Integration anderer APIs zu ermöglichen. Der Vorteil dieses Ansatzes ist die Möglichkeit, JAX-RS-Ressourcen der JSON-B-Konvertierungs- und Bean-Validierungstechnologie ohne zusätzliche explizite Konfiguration mit Ausnahme von Anmerkungen zu verwenden. In den vorherigen Beispielen haben wir gesehen, wie die in einzelnen Standards definierten Funktionen ohne zusätzlichen Aufwand zusammen verwendet werden können. Dies ist einer der größten Vorteile der Java EE-Plattform. Eine generische Spezifikation garantiert eine Kombination einzelner Standards. Programmierer können sich auf bestimmte Funktionen und Implementierungen verlassen, die vom Anwendungsserver bereitgestellt werden.
Einfach zu verwendender hochwertiger Code
Programmierer sind sich im Allgemeinen einig, dass Sie sich bemühen sollten, qualitativ hochwertigen Code zu schreiben. Hierfür sind jedoch nicht alle Technologien gleich gut geeignet.
Wie am Anfang des Buches erwähnt, sollte der Schwerpunkt der Anwendungsentwicklung auf der Geschäftslogik liegen. Im Falle von Änderungen in der Geschäftslogik oder dem Aufkommen neuen Wissens ist es erforderlich, das Domänenmodell sowie den Quellcode zu aktualisieren. Iteratives Refactoring ist erforderlich, um ein qualitativ hochwertiges Domänenmodell und den Quellcode als Ganzes zu erstellen und zu verwalten. Bemühungen, das Verständnis des Themenbereichs zu vertiefen, werden im Konzept des problemorientierten Designs beschrieben.
Es gibt viel Literatur zum Refactoring auf Codeebene. - , , . , . , .
- . , , — , , - . — , , . . , , .
, . , .
, , , . , , - . , , , - , . , . 7.
, . , , , . Java EE : , , . .
. , , , . . 6 , .
. , , , . , . , , . , . . , . - .
Über den Autor
(Sebastian Daschner) — Java-, , Java (EE). JCP, Java EE, JSR 370 374 . Java Java - Oracle.
IT-, JavaLand, JavaOne Jfokus. JavaOne Rockstar JavaOne 2016. Java (Steve Chin) Java, . JOnsen — Java, .
(Melissa McKay) — 15- , . Java-, . , , .
JCrete () JOnsen . IT- , JavaOne4Kids JCrete4Kids. JavaOne 2017 Denver Java User Group.
»Weitere Informationen zum Buch finden Sie auf
der Website des Herausgebers»
Inhalt»
Auszug20% Rabatt auf Gutschein für Händler - Java EE