Erstellen von Microservices mit Eclipse MicroProfile
1. Überblick
In diesem Artikel konzentrieren wir uns auf die Erstellung eines auf Eclipse MicroProfile basierenden Mikroservices.
Wir werden uns ansehen, wie Sie eine RESTful-Webanwendung mit JAX-RS-, CDI- und JSON-P-APIs schreiben.
2. Eine Microservice-Architektur
Einfach ausgedrückt, Microservices sind Software-Architekturen, die ein vollständiges System aus mehreren unabhängigen Diensten bilden.
Jeder konzentriert sich auf einen Funktionsumfang und kommuniziert mit den anderen über ein sprachunabhängiges Protokoll wie REST.
3. Eclipse MicroProfile
Eclipse MicroProfile ist eine Initiative zur Optimierung von Enterprise Java für die Microservices-Architektur. Es basiert auf einer Teilmenge von Java EE-WebProfile-APIs, sodass wir MicroProfile-Anwendungen wie Java EE-Anwendungen erstellen können.
Das Ziel von MicroProfile ist es, Standard-APIs für den Aufbau von Mikrodiensten zu definieren und tragbare Anwendungen über mehrere MicroProfile-Laufzeiten bereitzustellen.
4. Maven-Abhängigkeiten
Alle Abhängigkeiten, die zum Erstellen einer Eclipse MicroProfile-Anwendung erforderlich sind, werden von dieser Stücklistenabhängigkeit bereitgestellt:
org.eclipse.microprofile
microprofile
1.2
pom
provided
Der Bereich wird aufprovided festgelegt, da die MicroProfile-Laufzeit bereits die API und die Implementierung enthält.
5. Repräsentationsmodell
Beginnen wir mit der Erstellung einer schnellen Ressourcenklasse:
public class Book {
private String id;
private String name;
private String author;
private Integer pages;
// ...
}
Wie wir sehen können, gibt es keine Anmerkung zu dieserBook-Klasse.
6. CDI verwenden
Einfach ausgedrückt ist CDI eine API, die Abhängigkeitsinjektion und Lebenszyklusmanagement bietet. Dies vereinfacht die Verwendung von Enterprise-Beans in Webanwendungen.
Erstellen wir nun eine CDI-verwaltete Bean als Speicher für die Buchdarstellung:
@ApplicationScoped
public class BookManager {
private ConcurrentMap inMemoryStore
= new ConcurrentHashMap<>();
public String add(Book book) {
// ...
}
public Book get(String id) {
// ...
}
public List getAll() {
// ...
}
}
Wir kommentieren diese Klasse mit@ApplicationScoped, da wir nur eine Instanz benötigen, deren Status von allen Clients gemeinsam genutzt wird. Dafür haben wir einConcurrentMap als typsicheren In-Memory-Datenspeicher verwendet. Dann haben wir Methoden fürCRUD Operationen hinzugefügt.
Jetzt ist unsere Bean ein CDI-fähig und kann in die AnnotationBookEndpoint using the@Injectder Bean eingefügt werden.
7. JAX-RS API
Um eine REST-Anwendung mit JAX-RS zu erstellen, müssen Sie eine mit@ApplicationPath annotierteApplication-Klasse und eine mit@Path. annotierte Ressource erstellen
7.1. JAX RS-Anwendung
Die JAX-RS-Anwendung identifiziert den Basis-URI, unter dem die Ressource in einer Webanwendung verfügbar gemacht wird.
Erstellen wir die folgende JAX-RS-Anwendung:
@ApplicationPath("/library")
public class LibraryApplication extends Application {
}
In diesem Beispiel sind alle JAX-RS-Ressourcenklassen in der Webanwendung denLibraryApplicationzugeordnet, sodass sie unter demselbenlibrary-Pfad liegen. Dies ist der Wert vonApplicationPath annotation.
Diese mit Annotationen versehene Klasse teilt der JAX RS-Laufzeit mit, dass Ressourcen automatisch gefunden und verfügbar gemacht werden sollen.
7.2. JAX RS-Endpunkt
EineEndpoint-Klasse, auchResource-Klasse genannt, sollte eine Ressource definieren, obwohl viele der gleichen Typen technisch möglich sind.
Jede mit@Path annotierte Java-Klasse oder mindestens eine mit@Path or @HttpMethod annotierte Methode ist ein Endpunkt.
Jetzt erstellen wir einen JAX-RS-Endpunkt, der diese Darstellung verfügbar macht:
@Path("books")
@RequestScoped
public class BookEndpoint {
@Inject
private BookManager bookManager;
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getBook(@PathParam("id") String id) {
return Response.ok(bookManager.get(id)).build();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllBooks() {
return Response.ok(bookManager.getAll()).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response add(Book book) {
String bookId = bookManager.add(book);
return Response.created(
UriBuilder.fromResource(this.getClass())
.path(bookId).build())
.build();
}
}
Zu diesem Zeitpunkt können wir unter dem Pfad/library/booksin der Webanwendung auf die RessourceBookEndpointzugreifen.
7.3. JAX RS JSON-Medientyp
JAX RS unterstützt viele Medientypen für die Kommunikation mit REST-Clients, jedochEclipse MicroProfile restricts the use of JSON, da es die Verwendung der JSOP-P-API angibt. Daher müssen wir unsere Methoden mit@Consumes(MediaType.APPLICATION_JSON) und @Produces(MediaType.APPLICATION_JSON). kommentieren
Die Annotation@Consumeschränkt die akzeptierten Formate ein. In diesem Beispiel wird nur das JSON-Datenformat akzeptiert. Der HTTP-AnforderungsheaderContent-Type sollteapplication/json sein.
Die gleiche Idee steckt hinter der Annotation von@Produces. Die JAX RS Runtime sollte die Antwort auf das JSON-Format marshallen. Der HTTP-Header der AnforderungAccept sollteapplication/json. sein
8. JSON-P
JAX RS Runtime unterstützt JSON-P ab Werk, sodass wirJsonObject als Methodeneingabeparameter oder Rückgabetyp verwenden können.
Aber in der realen Welt arbeiten wir oft mit POJO-Klassen. Wir brauchen also eine Möglichkeit, das Mapping zwischenJsonObject und POJO durchzuführen. Hier spielt der JAX RS-Entitätsanbieter.
Um den JSON-Eingabestream für das POJO vonBookzu marshallen, müssen Sie eine KlasseBookMessageBodyReader: erstellen, um eine Ressourcenmethode mit einem Parameter vom TypBook, aufzurufen
@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class BookMessageBodyReader implements MessageBodyReader {
@Override
public boolean isReadable(
Class> type, Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return type.equals(Book.class);
}
@Override
public Book readFrom(
Class type, Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
return BookMapper.map(entityStream);
}
}
Wir machen den gleichen Prozess, um einBook für den JSON-Ausgabestream zu entmarschieren. Dabei wird eine Ressourcenmethode aufgerufen, deren RückgabetypBook, ist, indem einBookMessageBodyWriter: erstellt wird
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class BookMessageBodyWriter
implements MessageBodyWriter {
@Override
public boolean isWriteable(
Class> type, Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return type.equals(Book.class);
}
// ...
@Override
public void writeTo(
Book book, Class> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
JsonWriter jsonWriter = Json.createWriter(entityStream);
JsonObject jsonObject = BookMapper.map(book);
jsonWriter.writeObject(jsonObject);
jsonWriter.close();
}
}
DaBookMessageBodyReader undBookMessageBodyWriter mit@Provider versehen sind, werden sie automatisch von der JAX RS-Laufzeit registriert.
9. Erstellen und Ausführen der Anwendung
Eine MicroProfile-Anwendung ist portabel und sollte in jeder kompatiblen MicroProfile-Laufzeit ausgeführt werden. Wir werden erklären, wie unsere Anwendung inOpen Liberty erstellt und ausgeführt wird. Wir können jedoch jedes kompatible Eclipse MicroProfile verwenden.
Wir konfigurieren die Open Liberty-Laufzeit über eine Konfigurationsdateiserver.xml:
jaxrs-2.0
cdi-1.2
jsonp-1.0
Fügen wir das Pluginliberty-maven-plugin zu unserer pom.xml hinzu:
net.wasdev.wlp.maven.plugins
liberty-maven-plugin
2.1.2
io.openliberty
openliberty-runtime
17.0.0.4
zip
${basedir}/src/main/liberty/config/server.xml
${package.file}
${packaging.type}
false
project
/
${project.artifactId}-${project.version}.war
9080
9443
install-server
prepare-package
install-server
create-server
install-feature
package-server-with-apps
package
install-apps
package-server
Dieses Plugin kann über eine Reihe von Eigenschaften konfiguriert werden:
library
${project.build.directory}/${app.name}-service.jar
runnable
Das obige exec-Ziel erstellt eine ausführbare JAR-Datei, sodass unsere Anwendung ein unabhängiger Microservice ist, der isoliert bereitgestellt und ausgeführt werden kann. Wir können es auch als Docker-Image bereitstellen.
Führen Sie den folgenden Befehl aus, um eine ausführbare JAR-Datei zu erstellen:
mvn package
Und um unseren Microservice auszuführen, verwenden wir diesen Befehl:
java -jar target/library-service.jar
Dadurch wird die Open Liberty-Laufzeit gestartet und unser Service bereitgestellt. Wir können auf unseren Endpoint zugreifen und alle Bücher unter dieser URL abrufen:
curl http://localhost:9080/library/books
Das Ergebnis ist ein JSON:
[
{
"id": "0001-201802",
"isbn": "1",
"name": "Building Microservice With Eclipse MicroProfile",
"author": "example",
"pages": 420
}
]
Um ein einzelnes Buch zu erhalten, fordern wir diese URL an:
curl http://localhost:9080/library/books/0001-201802
Und das Ergebnis ist JSON:
{
"id": "0001-201802",
"isbn": "1",
"name": "Building Microservice With Eclipse MicroProfile",
"author": "example",
"pages": 420
}
Jetzt fügen wir ein neues Buch hinzu, indem wir mit der API interagieren:
curl
-H "Content-Type: application/json"
-X POST
-d '{"isbn": "22", "name": "Gradle in Action","author": "example","pages": 420}'
http://localhost:9080/library/books
Wie wir sehen können, lautet der Status der Antwort 201, was darauf hinweist, dass das Buch erfolgreich erstellt wurde, undLocation ist der URI, über den wir darauf zugreifen können:
< HTTP/1.1 201 Created
< Location: http://localhost:9080/library/books/0009-201802
10. Fazit
In diesem Artikel wurde gezeigt, wie ein einfacher Mikroservice auf der Basis von Eclipse MicroProfile erstellt wird, wobei JAX RS, JSON-P und CDI erläutert werden.
Der Code ist verfügbarover on Github; Da es sich um ein Maven-basiertes Projekt handelt, sollte es einfach zu importieren und so auszuführen sein, wie es ist.