Wir haben es uns zur Aufgabe gemacht, verschiedene Microframeworks anhand eines kleinen Anwendungsfalles zu evaluieren, der detaillierte Anwendungsfall wurde bereits in unserem ersten Blog-Post „https://thecattlecrew.net/2020/07/01/evaluierung-java-microframeworks-setting-the-scene/“ beschrieben. Heute werden wir uns auf das Microframework Javalin konzentrieren. Im Folgenden zeigen wir die wichtigsten Eigenschaften, Stärken und Schwächen von Javalin. Das Codebespiel ist unter diesen Link „https://github.com/opitzconsulting/javalin-demo“ zu finden.

Javalin ist ein einfaches Framework für die Programmiersprachen Java und Kotlin, welches geringerer Speicherverbrauch und schnelle Start-Up Zeit hat. Javalin wird unter der Apache 2.0 Licence veröffentlicht. 

Javalin ist eher eine Bibliothek als ein Framework und verfügt nur über sehr wenige Konzepte, die man lernen muss. Es müssen niemals Klassen erweitert und nur selten Schnittstellen implementiert werden. Außerdem verwendet Javalin weder Annotationen noch Reflection. 

Bei Javalin steht zudem das Thema Interoperabilität im Fokus. Apps können dabei transparent – ohne Ü„nderungen an Frameworkversionen oder -komponenten – sowohl in Java als auch in Kotlin entwickelt werden. Neben der JVM wird zudem GraalVM als Laufzeitumgebung unterstützt. Bei der Verwendung GraalVM Native Images können sowohl die Docker Imagegrößen, als auch die Startupzeiten massiv gesenkt werden, was bspw. für Serverless Apps sehr interessant ist. Weiterhin setzt das Framework technologisch auf Jetty.

Weitere Javalin-Features sind eine funktionale Schnittstelle namens Access Manager, mit der man die Authentifizierung und / oder Autorisierung pro Endpoint festlegen kann oder auch der Support für OpenAPI, der die Beschreibung der exponierten Schnittstellen erlaubt.

In diesem Teil haben wir erstmal allgemeine Informationen über Javalin gegeben. Im Folgenden betrachten wir wie eine Javalin Applikation entwickelt wird und die wichtigsten Eigenheiten und Elemente von Javalin.

Javalin Projekt erstellen und kompilieren

Das Erstellen eines Javalin-Projekts ist einfach und bereits nach ein paar Minuten kann man mit der Programmierung beginnen. Zuerst erstellt man ein Maven oder Gradle Projekt. Danach fügt man Javalin als normale Dependency hinzu. Wir haben mit Gradle ein Projekt erstellt und dort Javalin hinzugefügt, siehe Abbildung unterhalb.

1. dependencies {
2.    ...
3.    compile "org.slf4j:slf4j-simple:1.8.0-beta4"
4.    compile 'io.javalin:javalin:3.7.0'
5. }

Abbildung 1 "“ Gradle Projekt Dependencies/ build.gradle Datei

Nachdem wir unseres Javalin Projekt erstellt haben, können wir anfangen mit Javalin zu programmieren. Im folgenden Teil werden wir dann eine Beispiel Applikation mit Javalin betrachten.

Ein Java-Microservice mit Javalin

Nachdem nun ein Projekt erstellt ist, kommen wir zu der eigentlichen Stärke der Microframeworks – den Microservices. Wir benötigen für unsere Technologie Management Webseite jeweils eine Detailseite pro Technologie. Dafür haben wir einen Get-Handler (https://javalin.io/documentation#handlers) implementiert, welcher in der vierten Programmzeile in der Abbildung 2 zu sehen ist. Dank dieses Handlers kann man durch Aufrufen einiger Methoden Ergebnisse aus der Controller-Klasse erhalten. Der erste Bestandteil des Handlers, „/technologies/:key“ ist der URL.

1. public class TechnologyApplication {
2.    public static void main(String[] args) {
3.       Javalin app = Javalin.create().start(7000);
4.     	  app.get("/technologies/:key",
5.      TechnologiesController::getSpecialTech);
6.    }
7. }

Abbildung 2-Get Handler

Das Wort „key“ ist die Variable für die gewünschte Technologie. Beispielsweise werden alle Informationen zu der Technologie Angular unter folgender URL „http://localhost:7000/technologies/Angular“ zurückgegeben

Nachdem nun der Handler implementiert ist, muss noch der Controller sowie die Methode, die im Controller eingefügt wird, erstellt werden. Der Controller wird vom Handler aufgerufen (TechnologiesController, siehe Abb. 2 Zeile 5).

Javalin bietet für HTTP Anfragen einen Standardübergabeparameter vom Typ „Context“( https://javalin.io/documentation#context) (siehe Abb. 3 Zeile 5). Der Context bietet alles, was zur Bearbeitung benötigt wird (für mehr Details siehe bitte Abschnitt Context Objekt). In unserem Beispiel benutzen wir das Context Objekt, um alle Informationen unserer Technologie als Ergebnis zurückzugeben.

1. public final class TechnologiesController {
2. 	private TechnologiesController () { }
3.	static String [] availableTechnologies= {"Angular","4G", "Kotlin"};
4.	
5.	public static void getSpecialTech(Context ctx) {
6.	for(String tech : availableTechnologies){
7.		if(tech.contains(ctx.pathParam("special"))){
8.			ctx.result(tech);
9.			return;
10.		}
11.	}
12.	ctx.result("No Technologie :(");
13.	}
14. }

Abbildung 3-Controller Klasse

Handler in Javalin

Wenn man schon mal mit einem Java Framework wie zum Beispiel Spring Boot gearbeitet hat, sollte man Annotationen schon kennengelernt haben. Wenn wir bspw. eine Get-Anfrage in üblichen Frameworks bearbeiten wollen, annotieren wir unsere Methode mit @GET (siehe Abbildung 4 Zeile 1)

1. @GET
2. public static void exampleMethod (){
3. }

Abbildung 4- Beispiel für eine Annotation in anderen Frameworks

In Javalin gibt es jedoch genau diese Annotationen nicht! Diese Aufgabe übernehmen in Javalin die Handler. Es gibt drei Haupthandlertypen. Before Handler, Endpoint Handler und After Handler, wobei meistens der Endpoint Handler verwendet wird.

Endpoint Handler

Endpoint-Handler (GET, POST, PUT, DELETE) werden in der Mainklasse implementiert und für die Bearbeitung von Anfragen (Requets) verwendet. Abbildung 5 zeigt wie wir die Endpoint Handler implementiert haben.

1.  app.get("/technologies/:id", TechnologyController::getTechnology);
2.  app.delete("/technologies/:id",TechnologyController::removeTechnology);
3.  app.post("/technologies", TechnologyController::insertTechnology);
4.  app.put("/technologies", TechnologyController::updateTechnology);

Abbildung 5- Beispiele für Endpoint Handler

In Abbildung 5 sieht man, dass wir alle Handler in unserer Applikation benutzt haben. Durch die Namen der Handler, ist deren Funktion selbsterklärend. In Zeile 1 und 2 ist „id“ eine Variable. In dieser steht dann die Technologie id . Beispielsweise werden alle Informationen zu der Technologie Javalin mit id Nummer 2 unter folgender URL „http://localhost:7000/technologies/2“ zurückgegeben.

Javalin Context Objekt

Wie bereits erwähnt, bietet Javalin für HTTP Anfragen das Context Objekt (siehe Abbildung 6 Zeile 1).Beispielsweise kann man mit „context.pathParam(„id“);“ ein übergebener Pfad-Parameter ausgelesen werden (siehe Abbildung 6 Zeile 3). In unserem Beispiel benutzten wir dieses Context Objekt auch, um einen Status zurückzugeben (siehe Abbildung 6 Zeile 6).

1.	public static void getTechnology(Context context) {
2.	        DBService con = new DBService();
3.	        String string_id = context.pathParam("id");
4.	
5.	        if(string_id==null) {
6.	            context.status(404);
7.	            return;
8.	        }
9.	 "¦

Abbildung 6-Context Objekt

Datenbankverbindung

Wir wollen in unserem Beispiel die Technologien in einer Datenbank speichern oder auch gespeicherte Daten auslesen. Da Javalin dafür nichts Besonderes anbietet, haben wir uns für die Anbindung der Datenbank für die klassische Plain JDBC-Variante ohne die Verwendung eines Objektrelationalen Mapping (ORM) Frameworks entschieden. Dies macht auch die Anzahl der zusätzlich benötigten Dependencies überschaubar. Natürlich könnten auch entsprechende ORM-Frameworks wie bspw. Hibernate eingebunden und in der Implementierung verwendet werden.   

Wir haben in unsere Datenbankservice Klasse die Connection definiert und initialisiert. (siehe Abbildung 7 Zeile 5).“DB_URL“ (siehe Abbildung 7 Zeile 17) ist die URL-Adresse von unserem Datenbank und „DB_PORT“(siehe Abbildung 7 Zeile 17) ist die Portadresse der Datenbank, diese haben wir als Umgebungsvariablen gespeichert.

Außerdem haben wir in dieser Klasse die benötigen Methoden implementiert (siehe bitte Codebespiel in GitHub), um die Informationen in der Datenbank zu schreiben und auch Informationen aus der Datenbank auszulesen.

1.public class DBService {
2.    private Connection conn;
3.    public DBService() {
4.       try {
5.            conn = initConnection();
6.        } catch (ClassNotFoundException e) {
7.            e.printStackTrace();
8.        } catch (SQLException e) {
9.            e.printStackTrace();
10.        }
11.    }
12. private Connection initConnection() throws ClassNotFoundException, SQLException{ 
13. 
14.        Class.forName("org.postgresql.Driver");
15.        String user = "postgres"
16.        String password = "********";
17.        String dbUrl = System.getenv("DB_URL");
18.        String dbPort = System.getenv("DB_PORT");
19.        String dbConnectionString = "jdbc:postgresql://" + dbUrl + ":" + dbPort + "/postgres?ssl=false";
20. 
21.        return DriverManager.getConnection(dbConnectionString, user, password);
22.    }
23. }

Abbildung 7-Datenbankverbindung

Sonstige Features von Javalin

Asynchronität in Javalin

Wir haben in unserem Anwendungsbeispiele keine Asynchronität (https://javalin.io/news/2018/04/14/javalin-1.6.0-released.html) verwendet. Es ist jedoch ab Javalin 1.6.0 möglich eine asynchrone Request Bearbeitung zu verwenden, um die Performance zu verbessern und den Ressourcenverbrauch zu verringern.

Open API in Javalin

Ebenso ist noch zu erwähnen, das Javalin OpenAPI vollständig unterstützt, was bei viele anderen leichtgewichtigen Java-Frameworks nicht der Fall ist. Um OpenAPI Plugins nutzen zu können, sollte man „javalin-openapi“ als Dependency hinzufügen. ( https://javalin.io/plugins/openapi#openapioptions)).

Logging in Javalin

Für das Anwendungslogging bringt Javalin nichts Besonderes mit. Somit kann eine beliebige Logging-Implementierung, wie bspw. Slf4J verwendet werden. Dazu muss einfach nur die entsprechende Dependency in dem Projekt hinzugefügt werden. Mehr Informationen über Logging Optionen in Javalin findet man unter https://javalin.io/documentation#logging.

Zusammenfassung

Die Implementierung von Javalin ist ziemlich einfach. Man muss keine externen Dateien installieren. In wenigen Minuten kann man seine erste Javalin-Anwendung implementieren. Außerdem gibt es nicht so viele Funktionen von Javalin, daher empfanden wir, dass Javalin ein einfaches Framework ist, welches man ohne großen Lernaufwand nutzen kann. Nach einer Umfrage von Javalin benutzen 92% der Entwickler Javalin für REST APIs, das war bei uns ebenso der Fall. Es wird aber auch sehr oft für WebSockets und für Websites benutzt.

Obwohl Javalin ein sehr leichtgewichtiges Framework und einfach zu verstehen war, ist das Framework ziemlich neu, deswegen gibt es auch nur wenige andere Wissensquellen, deswegen hätten wir uns gefreut, wenn es Anwendungsbeispiele in der Javalin Dokumentation gegeben hätte, damit ein Einstieg ins Framework noch leichter gewesen wäre.

Alle Beiträge von Meryem Cigdem

Schreibe einen Kommentar