Commit a4231c15 authored by Blanke, Daniela's avatar Blanke, Daniela
Browse files

Update distributed-spring.html

parent eb801b55
Pipeline #8028 passed with stage
in 1 minute and 11 seconds
......@@ -21,7 +21,7 @@
<li><a href="https://spring.io/guides/gs/accessing-data-rest/">Einstieg in Spring Data REST</a></li>
</ul>
<p>Die zu entwickelnde REST-API soll Objekte zu den folgenden Entitätsklassen bereitstellen: <code>User</code>, <code>Product</code> und <code>Booking</code>. Der Zusammenhang der Klassen ist in der nächsten Abbildung veranschaulicht. Die API bildet die Datenhaltung für eine minimale Shop-Anwendung ab, in der authentifizierte Anwender (<code>User</code>) Produkte (<code>Product</code>) aus einem Produktkatalog auswählen und für diese beliebig viele Buchungen (<code>Booking</code>) anlegen und wieder entfernen können. Die hier entwickelte API soll in den folgenden Kapiteln zu den UI-Frameworks als gemeinsame Basis genutzt werden, d.h. die später vorgestellten Clients in <a href="#unit-javafx" class="navigate">JavaFX</a> und <a href="#unit-web" class="navigate">JQuery/Angular</a> greifen jeweils auf diese API zu. c
<p>Die zu entwickelnde REST-API soll Objekte zu den folgenden Entitätsklassen bereitstellen: <code>User</code>, <code>Product</code> und <code>Booking</code>. Der Zusammenhang der Klassen ist in der nächsten Abbildung veranschaulicht. Die API bildet die Datenhaltung für eine minimale Shop-Anwendung ab, in der authentifizierte Anwender (<code>User</code>) Produkte (<code>Product</code>) aus einem Produktkatalog auswählen und für diese beliebig viele Buchungen (<code>Booking</code>) anlegen und wieder entfernen können. Die hier entwickelte API soll in den folgenden Kapiteln zu den UI-Frameworks als gemeinsame Basis genutzt werden, d.h. die später vorgestellten Clients in <a href="#unit-javafx" class="navigate">JavaFX</a> und <a href="#unit-web" class="navigate">JQuery/Angular</a> greifen jeweils auf diese API zu.</p>
<img src="media/distributed_spring_entities.png" style="width:540px">
<label>Datenmodell der entwickelten REST-API mit Spring Data</label>
......@@ -176,7 +176,7 @@ Content-type: application/hal+json; charset=utf-8
} --></code></pre></div>
</div>
<p>Dass die HTTP-Response nicht nur die Daten selbst sondern auch weiterführende Links zur Navigation innerhalb der API enthält, entspricht dem sogenannten <a href="http://restcookbook.com/Basics/hateoas/">HATEOAS</a>-Prinzip: <i>Hypermedia As The Engine Of Application State</i>. Da der Client bei einer REST-API (im Gegensatz zur WSDL bei SOAP-Webservices) keine formale Schnittstellenbeschreibung erhält, sind die Entwickler, die eine REST-API aufrufen möchten, auf eine gute Dokumentation angewiesen, in der die mögliche Parametrisierung der API-Endpunkte, die über die Konventionen hinausgeht, beschrieben wird. Die grundlegende Idee von HATEOAS ist es, diese Dokumentation in die API selbst einzubetten. Daher werden neben den angefragten Daten auch Links zurückgegeben, die potentielle Transitionen ausgehend von der aktuellen Anfrage zur nächsten Anfrage angeben. Die REST-API wird auf diese Weise als Zustandsautomat betrachtet, durch den mittels Hypermedia (= Repräsentation einer Ressource inkl. Links) navigiert werden kann. Die nächste Abbildung zeigt einen kleinen Ausschnitt einer REST-API als Zustandsautomat.</p>
<p>Dass die HTTP-Response nicht nur die Daten selbst, sondern auch weiterführende Links zur Navigation innerhalb der API enthält, entspricht dem sogenannten <a href="http://restcookbook.com/Basics/hateoas/">HATEOAS</a>-Prinzip: <i>Hypermedia As The Engine Of Application State</i>. Da der Client bei einer REST-API (im Gegensatz zur WSDL bei SOAP-Webservices) keine formale Schnittstellenbeschreibung erhält, sind die Entwickler, die eine REST-API aufrufen möchten, auf eine gute Dokumentation angewiesen, in der die mögliche Parametrisierung der API-Endpunkte, die über die Konventionen hinausgeht, beschrieben wird. Die grundlegende Idee von HATEOAS ist es, diese Dokumentation in die API selbst einzubetten. Daher werden neben den angefragten Daten auch Links zurückgegeben, die potentielle Transitionen ausgehend von der aktuellen Anfrage zur nächsten Anfrage angeben. Die REST-API wird auf diese Weise als Zustandsautomat betrachtet, durch den mittels Hypermedia (= Repräsentation einer Ressource inkl. Links) navigiert werden kann. Die nächste Abbildung zeigt einen kleinen Ausschnitt einer REST-API als Zustandsautomat.</p>
<img src="media/distributed_spring_hateoas.png" style="width:600px">
<label>REST-API als Zustandsautomat</label>
......@@ -241,7 +241,7 @@ Content-type: application/hal+json; charset=utf-8
"page": { "size": 3, "totalElements": 15, "totalPages": 5, "number": 0 }
} --></code></pre>
<p>Die automatisch von Spring generierten Ressourcen-Methoden für ein <code>CrudRepository</code> können über verschiedene Wege angepasst werden. Es kann eine Klasse angelegt werden, die das Interface implementiert und die Methoden überschreibt. Alternativ kann eine Klasse versehen mit der Annotation <code>@RestController</code> angelegt und auf dem Pfad der Ressource registriert wird. Beide Wege erlauben das Verhalten der HTTP-Methoden individuell anzupassen. Im folgenden Code-Beispiel überschreibt die Klasse <code>UserController</code> die auf dem Pfad <code>/users</code> registrierten Methoden für POST und GET des Interface <code>UserRepository</code> (Zeilen 4-5). Bei einer GET-Anfrage werden z.B. nur noch die Namen der vorhandenen User ohne weitere Attribute der Klasse ausgegeben (Zeilen 22-26). Die Methode <code>findByName</code> im Interface <code>UserRepository</code> ist ohnehin nicht Teil der REST-API, da sie nicht mit einer Annotation <code>@RestResource</code> versehen ist. Im <code>UserRepository</code> werden explizit noch die Methoden GET und DELETE für den Pfad <code>/users/&lt;id></code> deaktiviert.</p>
<p>Die automatisch von Spring generierten Ressourcen-Methoden für ein <code>CrudRepository</code> können über verschiedene Wege angepasst werden. Es kann eine Klasse angelegt werden, die das Interface implementiert und die Methoden überschreibt. Alternativ kann eine Klasse, versehen mit der Annotation <code>@RestController</code>, angelegt und auf dem Pfad der Ressource registriert werden. Beide Wege erlauben das Verhalten der HTTP-Methoden individuell anzupassen. Im folgenden Code-Beispiel überschreibt die Klasse <code>UserController</code> die auf dem Pfad <code>/users</code> registrierten Methoden für POST und GET des Interface <code>UserRepository</code> (Zeilen 4-5). Bei einer GET-Anfrage werden z.B. nur noch die Namen der vorhandenen User ohne weitere Attribute der Klasse ausgegeben (Zeilen 22-26). Die Methode <code>findByName</code> im Interface <code>UserRepository</code> ist ohnehin nicht Teil der REST-API, da sie nicht mit einer Annotation <code>@RestResource</code> versehen ist. Im <code>UserRepository</code> werden explizit noch die Methoden GET und DELETE für den Pfad <code>/users/&lt;id></code> deaktiviert.</p>
<ul class="nav nav-tabs" id="spring3-tabs" role="tablist">
......@@ -310,7 +310,7 @@ Request URL: http://localhost:8080/users/1
<h4>Reaktive Web-Anwendungen mit Spring</h4>
<p>Das ursprüngliche Spring-Framework zur Entwicklung von Web-Anwendungen auf Basis der <a href="https://jcp.org/en/jsr/detail?id=369">Servlet API</a> nennt sich <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html">Spring MVC</a>. Neu in der aktuellen Version 5 des Spring-Frameworks ist die Unterstützung der <a href="http://www.reactive-streams.org/">Reactive Streams API</a> auf Basis der Bibliothek <a href="https://projectreactor.io/">Reactor</a>. Dieser alternative Architekturansatz nennt sich <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html">Spring WebFlux</a> und ist auf asynchrone und nicht-blockierende Kommunikation ausgerichtet. Die folgende Definition aus der Spring-Dokumentation erklärt, was wir unter dem Begriff <a href="https://de.wikipedia.org/wiki/Reaktive_Programmierung">Reaktive Programmierung</a> verstehen.</i></p>
<p>Das ursprüngliche Spring-Framework zur Entwicklung von Web-Anwendungen auf Basis der <a href="https://jcp.org/en/jsr/detail?id=369">Servlet API</a> nennt sich <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html">Spring MVC</a>. Neu in der aktuellen Version 5 des Spring-Frameworks ist die Unterstützung der <a href="http://www.reactive-streams.org/">Reactive Streams API</a> auf Basis der Bibliothek <a href="https://projectreactor.io/">Reactor</a>. Dieser alternative Architekturansatz nennt sich <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html">Spring WebFlux</a> und ist auf asynchrone und nicht-blockierende Kommunikation ausgerichtet. Die folgende Definition aus der Spring-Dokumentation erklärt, was wir unter dem Begriff <a href="https://de.wikipedia.org/wiki/Reaktive_Programmierung">Reaktive Programmierung</a> verstehen.</p>
<div class="cite"><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html">"The term, “reactive,” refers to programming models that are built around reacting to change — network components reacting to I/O events, UI controllers reacting to mouse events, and others. In that sense, non-blocking is reactive, because, instead of being blocked, we are now in the mode of reacting to notifications as operations complete or data becomes available.
There is also another important mechanism that we on the Spring team associate with “reactive” and that is non-blocking back pressure. In synchronous, imperative code, blocking calls serve as a natural form of back pressure that forces the caller to wait. In non-blocking code, it becomes important to control the rate of events so that a fast producer does not overwhelm its destination." (Spring Docs)</a></div>
......@@ -325,7 +325,7 @@ There is also another important mechanism that we on the Spring team associate w
<ul class="nav nav-tabs" id="flux1-tabs" role="tablist">
<li class="nav-item"><a href="#flux1-tabs-controller" class="nav-link active" data-toggle="tab" role="tab">CounterController</a></li>
<li class="nav-item"><a href="#flux1-tabs-client" class="nav-link" data-toggle="tab" role="tab">counter.html</code></a></li>
<li class="nav-item"><a href="#flux1-tabs-client" class="nav-link" data-toggle="tab" role="tab">counter.html</a></li>
</ul>
<div class="tab-content" id="flux1-tabs-content">
<div class="tab-pane show active" id="flux1-tabs-controller" role="tabpanel">
......@@ -388,14 +388,14 @@ public class CounterController {
<li>Wenn der Datenstrom serverseitig geschlossen wird oder in anderen Fehlerfällen, wird die EventSource geschlossen (Zeilen 10-13). Andernfalls würde der Client gemäß SSE-Protokoll versuchen die Verbindung neu aufzubauen.</li>
</ul>
<p>Im nächsten Code-Beispiel soll die Quelle eines Datenstroms ein MongoDB-Datenbanksystem sein. Jedes Mal wenn neue Dokumente in eine Collection innerhalb der MongoDB-Datenbank eingefügt werden, soll die serverseitige Komponente auf Basis von <i>Spring WebFlux</i> einen registrierten Client darüber benachrichtigen. Die Dokumente könnten z.B. Tweets sein, die aus einer unendlichen externen Quelle bezogen werden. Die Architektur entspricht damit durchgängig dem reaktiven Programmiermodell.</p>
<p>Im nächsten Code-Beispiel soll die Quelle eines Datenstroms ein MongoDB-Datenbanksystem sein. Jedes Mal, wenn neue Dokumente in eine Collection innerhalb der MongoDB-Datenbank eingefügt werden, soll die serverseitige Komponente auf Basis von <i>Spring WebFlux</i> einen registrierten Client darüber benachrichtigen. Die Dokumente könnten z.B. Tweets sein, die aus einer unendlichen externen Quelle bezogen werden. Die Architektur entspricht damit durchgängig dem reaktiven Programmiermodell.</p>
<ul class="nav nav-tabs" id="flux2-tabs" role="tablist">
<li class="nav-item"><a href="#flux2-tabs-controller" class="nav-link active" data-toggle="tab" role="tab">TweetController</a></li>
<li class="nav-item"><a href="#flux2-tabs-repo" class="nav-link" data-toggle="tab" role="tab">TweetRepository</a></li>
<li class="nav-item"><a href="#flux2-tabs-model" class="nav-link" data-toggle="tab" role="tab">Tweet</a></li>
<li class="nav-item"><a href="#flux2-tabs-starter" class="nav-link" data-toggle="tab" role="tab">TweetStarter</a></li>
<li class="nav-item"><a href="#flux2-tabs-client" class="nav-link" data-toggle="tab" role="tab">tweets.html</code></a></li>
<li class="nav-item"><a href="#flux2-tabs-client" class="nav-link" data-toggle="tab" role="tab">tweets.html</a></li>
</ul>
<div class="tab-content" id="flux2-tabs-content">
<div class="tab-pane show active" id="flux2-tabs-controller" role="tabpanel">
......@@ -508,7 +508,7 @@ public class TweetStarter implements CommandLineRunner {
<ul>
<li><b>TweetController</b>: Als Teil der API wird ein Datenstrom unter dem Pfad <code>/tweets</code> registriert (Zeilen 10-13). Es wird eine Methode aus dem zugehörigen <code>TweetRepository</code> aufgerufen, um auf die Datenbank zuzugreifen.</li>
<li><b>TweetRepository</b>: Das Interface erweitert <code>ReactiveMongoRepository&lt;Tweet, String></code> und ist damit ein spezielles reaktives Repository. JDBC-Datenquellen können nicht als reaktives Repository eingesetzt werden. Bei einer Anfrage an die Datenbank gibt die Java-API von MongoDB einen Cursor vom Typ <a href="http://api.mongodb.com/java/current/com/mongodb/DBCursor.html"><code>com.mongodb.DBCursor</code></a> zurück, über den ähnlich einem <code>java.sql.ResultSet</code> iteriert werden kann, um das Ergebnis der Anfrage zu verarbeiten. Per Default schließt MongoDB diesen Cursor, wenn über alle seine Objekte iteriert worden ist. Damit würde aber auch der Stream beendet.<br>MongoDB erlaubt es für sogenannte <a href="https://docs.mongodb.com/manual/core/capped-collections/"><i>Capped Collections</i></a> einen <a href="https://docs.mongodb.com/manual/core/tailable-cursors/"><i>Tailable Cursor</i></a> zu verwenden, der geöffnet bleibt, nachdem alle ursprünglich zurückgegebenen Objekte verarbeitet worden sind. Die Methoden eines <code>ReactiveMongoRepository</code> aus <a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.reactive.repositories.infinite-streams"><i>Spring Data MongoDB</i></a> können mit der Annotation <a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.reactive.repositories.infinite-streams"><code>@Tailable</code></a> versehen werden, damit sie einen deartigen nicht abgeschlossenen, unendlichen Datenstrom zurückgeben, d.h. das zurückgegebene <code>Flux</code>-Objekt ist noch nicht beendet. Nur in diesem Fall wird über die API eine SSE-EventSource veröffentlicht. Die Bezeichnung der Annotation <code>@Tailable</code> ist übrigens an den Linux-Befehl <a href="https://en.wikipedia.org/wiki/Tail_(Unix)#File_monitoring"><code>tail -f</code></a> angelehnt.</li>
<li><b>TweetRepository</b>: Das Interface erweitert <code>ReactiveMongoRepository&lt;Tweet, String></code> und ist damit ein spezielles reaktives Repository. JDBC-Datenquellen können nicht als reaktives Repository eingesetzt werden. Bei einer Anfrage an die Datenbank gibt die Java-API von MongoDB einen Cursor vom Typ <a href="http://api.mongodb.com/java/current/com/mongodb/DBCursor.html"><code>com.mongodb.DBCursor</code></a> zurück, über den ähnlich einem <code>java.sql.ResultSet</code> iteriert werden kann, um das Ergebnis der Anfrage zu verarbeiten. Per Default schließt MongoDB diesen Cursor, wenn über alle seine Objekte iteriert worden ist. Damit würde aber auch der Stream beendet.<br>MongoDB erlaubt es für sogenannte <a href="https://docs.mongodb.com/manual/core/capped-collections/"><i>Capped Collections</i></a> einen <a href="https://docs.mongodb.com/manual/core/tailable-cursors/"><i>Tailable Cursor</i></a> zu verwenden, der geöffnet bleibt, nachdem alle ursprünglich zurückgegebenen Objekte verarbeitet worden sind. Die Methoden eines <code>ReactiveMongoRepository</code> aus <a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.reactive.repositories.infinite-streams"><i>Spring Data MongoDB</i></a> können mit der Annotation <a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.reactive.repositories.infinite-streams"><code>@Tailable</code></a> versehen werden, damit sie einen derartigen nicht abgeschlossenen, unendlichen Datenstrom zurückgeben, d.h. das zurückgegebene <code>Flux</code>-Objekt ist noch nicht beendet. Nur in diesem Fall wird über die API eine SSE-EventSource veröffentlicht. Die Bezeichnung der Annotation <code>@Tailable</code> ist übrigens an den Linux-Befehl <a href="https://en.wikipedia.org/wiki/Tail_(Unix)#File_monitoring"><code>tail -f</code></a> angelehnt.</li>
<li><b>TweetStarter</b>: In der überschriebenen Methode <code>run</code> wird zuerst die verwendete Collection in eine auf max. 5 Dokumente begrenzte <i>Capped Collection</i> gewandelt (Zeilen 18-20). Anschließend wird ein HTTP-Request vorbereitet (Zeilen 23-25), der in einer Endlosschleife alle 3 Sekunden ausgeführt wird (Zeile 36), um den Text für einen <a href="https://baconipsum.com/">fleischlastigen Lorem Ipsum-Tweet</a> anzufragen (Zeile 30) und diesen in der <i>Capped Collection</i> zu speichern (Zeilen 31-32).</li>
<li><b>tweets.html</b>: Der Client in <code>tweets.html</code> baut eine Verbindung zur EventSource auf (Zeile 6). Die EventSource emittiert neue Tweets an den Client über die EventHandler-Funktion (Zeilen 7-11), innerhalb derer die Tweets dem DOM hinzugefügt werden.</li>
</ul>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment