#2: Spring Boot in VSCode und Docker

In diesem Artikel soll es darum gehen, Visual Studio Code (folgend VSCode) so einzurichten, dass damit eine Java Spring Boot Anwendung entwickelt werden kann. Basis für dieses Tutorial ist der Artikel zur Einrichtung von VSCode mit Docker und der WSL2. Diesen solltest du durcharbeiten und ein frisches Debian Image parat haben und Docker-Desktop dafür konfiguriert sein, bevor du hier weitermachst.

Einrichten des WSL Images

Um sinnvoll mit VSCode in der Linux Umgebung eine Java erstellen zu können, braucht du unbedingt ein paar Entwickler-Leckerlis. Starte hierfür eine Konsole in der WSL mit “wsl –distribution Debian“, und installiere Dir alle Tools die du braucht. Für dieses Tutorial sieht das Script dafür wie folgt aus:

#!/bin/bash
apt update
apt install curl -y
apt install openjdk-11-jre -y
apt install openjdk-11-jdk -y
apt install maven -y
apt install net-tools -y
apt install git -y

touch /etc/profile.d/custom.sh

echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' >> /etc/profile.d/custom.sh
echo 'export PATH=${PATH}:${JAVA_HOME}/bin' >> /etc/profile.d/custom.sh
echo 'export M2_HOME=/usr/share/maven' >> /etc/profile.d/custom.sh
echo 'export PATH=${PATH}:${M2_HOME}/bin' >> /etc/profile.d/custom.sh

# Allow user admin to use docker (docker must be installed)
usermod -aG docker admin

Ein paar weitere Anpassungen sind darüber hinaus noch im Usercontext (hier “admin”) notwendig.

#!/bin/bash
# Workaround for: docker.credentials.errors.InitializationError: docker-credential-desktop.exe not installed or not available in PATH
echo '{"_credsStore":"desktop.exe"}' > ~/.docker/config.json


# Basic configuration of git
git config --global user.name "Your Name"
git config --global user.email "youremail@yourdomain.com"

Einrichten von VSCode

Arbeitsverzeichnis öffnen

Ist das WSL-Image eingerichtet, legst du erstmal einen neuen Ordner an, der die Basis für dein “VSCode Java Spring Boot” Projekt darstellt.

Du kannst direkt auf ein Windows Arbeitsverzeichnis mit “mnt/c/…” zugreifen. Allerdings ist dies nicht zu empfehlen, das die Leistung des Dateisystems das einzige ist, was bei der WSL2 gegenüber der WSL1 sich wirklich verschlechtert (siehe hier). Das merkst du nicht bei ein paar Dateien, wohl aber wenn du mehrere 1000 Dateien in dein Arbeitsverzeichnis eingebunden hast. Daher ist empfohlen, die Projektverzeichnisse immer in der WSL selber abzulegen. In den folgenden Artikeln nutze ich dafür das Verzeichnis “/home/admin/dev/demo“, wobei “demo” das Arbeitsverzeichnis bildet.

VSCode öffnet bem nächsten Start immer automatisch den zuletzt geöffneten Ordner und verbindet sich auch automatisch mit der zuletzt geöffneten WSL. Du brauchst dieses Schritt also nicht jedesmal wiederholen.

Wenn du mit mehreren Workspaces arbeiten willst, werden Dir im Rechtsklick-Kontextmenü von VSCode die verschiedenen Workspaces die du zuletzt geöffnet hattest direkt angeboten. Diese kannst du auch dauerhaft “anpinnen”.

Möchtest du von deinem Windows System auf das Arbeitsverzeichnis in deiner WSL zugreifen, ist dies auch kein Problem. Rufe in deinem Explorer einfach den Pfad “\\wsl$” auf. Dann bekommt du deinen WSL Images angezeigt und kansnt ganz normal da durch navigieren.

Installieren der Extensions

Nach Start von VSCode verbindest du dich mit erstmal mit deiner WSL (siehe Teil 1), wechselst in den “Extensions” Bereich und installierst die folgenden essentiellen Extensions zur Java Entwicklung in deiner WSL (mit Klick auf “Install on WSL: Debian”):

  • Java Extension Pack (enthält die folgenden)
    • Language Support for Java
    • Visual Studio IntelliCode
    • Debugger for Java
    • Maven for Java
    • Java Test runner
    • Project Manager for Java
  • Spring Initializr Java Support
  • Docker
  • Weitere Empfehlungen
    • Todo Tree (Durchsucht alle Verzeichnisse nach “TODO” und “FIXME” und stellt diese in einem Baum dar).
    • REST Client (Wer braucht schon Postman, hier kannst du alle Test-Requests in einer Textdatei in deinem Projekt speichern und direkt ausführen)
    • ApexSQL Database Power Tools for VS Code (Datenbankmanagment für MySQL/MariaDB)

Tip: Neben dieser manuellen Installation, kannst du auch einen Ordner “.vscode” in deinem zuvor geöffneten Arbeitsverzeichnis anlegen. In diesen Ordner wird die Datei “extensions.json” mit folgendem Inhalt angelegt:

{
     "recommendations": [
         "vscjava.vscode-java-pack",
         "vscjava.vscode-spring-initializr",
         "ms-azuretools.vscode-docker",
         "gruntfuggly.todo-tree",
         "humao.rest-client",
        "vs-publisher-988541.apexsql-power-tools"
     ],
     "unwantedRecommendations": [     ]
}

Beim nächsten Start von VSCode, bekommt ein Anwender die Aufforderung, alle gelisteten Extensions automatisch zu installieren und kann dies mit einem Knopfdruck erledigen. Besonders in verteilten Teams ist dies überaus praktisch. Wir werden folgend des .vscode Ordner auch öfters verwenden.

Tip 2: Leg den “.vscode” Ordner in deiner WSL an und exportiere (siehe Teil 1) dann das Image um es an dein Team zu verteilen. Damit arbeiten auch alle automatisch mit den gleichen Settings.

Initialisieren einer ersten Spring Boot Anwendung

Ich zeige in diesem Artikel nur, wie eine Spring Boot Anwendung initialisiert wird. Diese Anwendung wird aber dann als Grundlage für die Folge-Artikel verwendet. Die Anwendung heißt schlicht “telemetry” und soll es ermöglichen, Telemetrydaten über ein Betriebssystem in einer Datenbank zu sammeln.

Starte nun mit “Ctrl + Shift + P” (in der default Konfiguration von VSCode) das VSCode Command-Eingabefeld und tippe “Spring Init” um zum Spring Initializr zu gelangen. Normalerweise würde man sein Spring Projekt über die Website “https://start.spring.io/” anlegen. Über die Extension ist dieser Umweg nicht mehr notwendig und der nun folgende Assistent fragt alle notwendigen Schritte ab.

Wir erstellen ein Maven Projekt

Ihr gebt nun die aktuellste Spring Version an, wählt Java als Programmiersprache und definiert euren Projektnamen als Domainname in “rückwärts”. Folgend sind noch einmal alle Einstellungen notiert, wie ich sie zum Zeitpunkt dieses Artikels verwendet habe.

  • Spring Boot Version: 2.3.4
  • Projekt language: Java
  • Group ID: de.frickeldave.fleckerteppich (Ich finde ein super Name für eine Ansammlung von Microservices 😉 )
  • Artefact Id: telemetry
  • packaging type: JAR
  • Java Version: 11
  • Dependencies:
    • Spring web
  • Pfad: /home/admin/dev/demo

Bei der Verwendung WSL remote Extension ist es ggf. noch notwendig, den Explorer manuell zu aktualisieren. Nach dem Refresh ist das Verzeichnis “telemetry” verfügbar.

Verwalten von Abhängigkeiten

Du kannst die Abhängigkeiten direkt in der pom.xml deines Projektes einsehen und modifizieren. Willst du z.B. “Spring Web” in der Release-Version 5.2.9 in dein Projekt einfügen, gehe auf die Website von Maven-Central und lade dort die fertige Notation für dein pom.xml herunter. Diese wird in die pom.xml in den Bereich der “Dependencies” übernommen und anschließend die Projektkonfiguration aktualisiert (siehe Folgekapitel).

Alternativ dazu kannst du die maven dependency auch direkt über Visual Studio Code einpflegen. Öffne hierfür den Java Dependency-Viewer und klicke auf “+”. Anschließend kannst du die “Run-Box” verwenden um maven central zu durchsuchen.

Hinzufügen einer maven dependency
Durchsuchen von maven central

Aktualisieren der Projektkonfiguration

Legst du nun einen neue Datei “xyz.java” an, wirst du feststellen, dass weder der package-pfad notiert ist, noch der Klassennamen. Von einer IDE wird natürlich schon erwartet, dass sie Grundkonstrukte neuer Dateien selbstständig zur Verfügung stellt. Dies geht natürlich auch in VSCode für deine Java Objekte, allerdings ist es notwendig die “Projektkonfiguration” zu aktualisieren. Du kannst dies mit der Tastenkombination “Shift + Alt +U”, im Kontextmenü der pom.xml oder unten rechts in der Symbolleiste tun.

Update der Projektkonfiguration

Debug Konfigurationen

Spring Boot folgt dem Paradigma “Konvention über Konfiguration”. Die Bezeichnung “Paradigma” ist hier bewusst gewählt: In dem Moment in dem du irgendwie “basteln” musst, solltest du noch mal nen Kaffee schlürfen und ein wenig im Netz suchen ob dein Problem nicht schon irgendwie wie Spring Boot gelöst ist.

Ein Beispiel zur Verdeutlichung:

Ich wollte in unterschiedlichen Situationen (TEST, PROD) verschiedene DB-Server ansprechen. Meine erste Reaktion darauf war, dass ich überlegt habe, wie ich beim Deployment die Konfigurationsdateien (application.properties) tauschen kann. Nach einigem Überlegen stellte ich mir die Frage, dass ich sicher nicht der erste mit dem Problem bin und bin relativ schnell bei spring-profiles gelandet, die es ermöglichen unterschiedliche Konfigurationen aufgrund eines Parameters aufzurufen. Die Konfigurationsdaten müssen dafür nur einem Namensschema entsprechen (Convention-over-Configuration). Problem gelöst. Die gleiche Funktionalität möchte ich auch beim debuggen meiner Spring Boot Anwendung in VSCode nutzen,wofür uns die launch Konfigurationen zur Verfügung stehen.
Damit das folgende Tutorial funktioniert, musst du nun “spring-boot-starter” in deine pom.xml übernehmen und die Konfiguration aktualisieren.

Anlegen aller benötigten Konfigurationsdateien

Um die Nutzung verschiedener Konfiguration zu testen, ohne gleich mit einer Datenbank rumexperimentieren zu müssen, nutzen wir die Spring Boot Eigenschaft “spring.banner.location“. Mit dieser können wir den Banner der standardmäßig beim Start angezeigt wird, modifizieren. Normalerweise wird das folgende angezeigt, wenn du deine Spring Boot Applikation startest:

Navigier nun in das Verzeichnis “src/main/resources” deines Projektes. Dort befindet sich eine Datei “application.properties“, die für die Anwnedungskonfiguration zuständig ist. In diese tragen wir nur “spring.output.ansi.enabled=always” ein, damit wir die Ausgabe schön farbig gestalten können. Die Ausgabe kann mit Variablen beliebig modifiziert werden. Hier findest du eine gute Beschreibung dazu.

Nun legen wir die folgenden zusätzlichen Dateien in “src/main/resources” an:

  • application-prod.properties
  • application-test.properties
  • banner.txt
  • banner-prod.txt
  • banner-test-txt

In die “property”-Dateien trägst du nun die jeweilige Banner Datei ein und füllst die Textdateien mit einem Inhalt deiner Wahl, der zu der jeweiligen Umgebung passt.

  • application-prod.properties: spring.banner.location=classpath:banner-prod.txt
  • application-test.properties: spring.banner.location=classpath:banner-test.txt

In die Datei “application.properties” muss kein Banner explizit eingetragen werden, da Spring Boot immer nach der banner.txt Datei sucht. Weiterhin bemerkenswert ist, dass wir “spring.output.ansi.enabled=always” ausschließlich in in der “application.properties” Datei eintragen müssen. Wir können daraus also lernen:
“Die application.properties” Datei wird immer ausgewertet und deren Werte übernommen, sofern die Werte nicht in einer anderen, dem Profil zugeordneten, Datei überschrieben werden.

Sind alle Daten angelegt, muss einmal “Update project configuration” auf der pom.xml ausgeführt werden.

Anlegen der Debug Konfiguration

Wenn noch nicht geschehen, legst du nun das Verzeichnis “.vscode” in deinem Arbeitsverzeichnis (NICHT Projektverzeichnis, also ganz oben auf der root) an. In diesem wird die Datei launch.json mit folgendem Inhalt erstellt.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Debug",
            "request": "launch",
            "mainClass": "de.frickeldave.fleckerlteppich.telemetry.TelemetryApplication",
            "args": ""
        },
        {
            "type": "java",
            "name": "Debug (test)",
            "request": "launch",
            "mainClass": "de.frickeldave.fleckerlteppich.telemetry.TelemetryApplication",
            "args": "--spring.profiles.active=test"
        },
        {
            "type": "java",
            "name": "Debug (prod)",
            "request": "launch",
            "mainClass": "de.frickeldave.fleckerlteppich.telemetry.TelemetryApplication",
            "args": "--spring.profiles.active=prod"
        }
    ]
}

Hinweis: In der von mir verwendeten VSCode Version war es noch notwendig, VSCode einmal neu zu starten, damit die geänderte launch.json auch verwendet wird.

Nun kannst du in deiner “Run” Ansicht direkt die drei Debug Konfigurationen über das Auswahlfeld rechts neben dem “Play” Button starten.

Starten in der “Test”-Konfiguration

Debug Konfiguration um den Start von Docker Containern erweitern

In einem der folgenden Artikel werde ich euch das Thema “JPA” und Datenbankanbindung beschreiben. In dem Artikel werden wir wahlweise eine H2 oder mariadb Datenbank integrieren. Damit beide Datenbanken in VSCode in deinem Java Projekt zum testen verfügbar sind ohne diese auf dem Entwicklerarbeitsplatz installieren zu müssen, wollen wir die mariadb über docker container zur Verfügung stellen.

Tip: Wir nutzen an dieser Stelle aus Gründen der Einfachheit das Standard mariadb image von docker hub. Im Enterprise Umfeld empfehle ich die Erstellung eines eigenen BaseImages (z.B. auf Basis von Alpine) in dem alle notwendigen Anpassungen für das eigene Netzwerk (z.B. Zertiifkate) enthalten sind. Auf Basis dieses Images wird dann ein eigenes mariadb image auf Basis der Vererbung in Docker aufgesetzt.

Erstellen der Docker Umgebung

Als erstes erstellst du die Datei “docker-compose-test.yml” in telemetry-Projektverzeichnis. Ich gehe hier davon aus, dass wenn die Debug-Konfiguration “Debug (test)” gestartet wird, auch automatisch eine mariadb Datenbank zur Verfügung gestellt werden soll. Diese compose Datei sieht wie folgt aus:

version: '3.7'

services:
  mariadb:
    image: mariadb:latest
    restart: "no"
    container_name: telemetrydb
    ports:
      - "3306:3306"
    networks: 
      - backend
    environment:
      - MYSQL_ROOT_PASSWORD=root123
      - MYSQL_DATABASE=telemetry
      - MYSQL_USER=telemetryadmin
      - MYSQL_PASSWORD=admin123
networks:
  backend:
    name: backend

Du kannst nun testen, ob die mariadb erreichbar ist. Mach eine wsl Konsole auf, wechsel in das Projektverzeichnis und starte den Container mit “docker-compose -f ./docker-compose-test.yml up“.

Mit der Apex Datenbankmanagement Extension (oder der MySQL Workbench) kannst du den Zugriff testen.

Verbindung zur Datenbank herstellen
Der Apex Datenbank-Explorer

Einbinden von mariadb in die launch Konfiguration

Funktioniert die mariadb, kann der Start mit in dem debug Prozess eingebunden werden. Hierzu fügst du das Argument “preLaunchTask” in die “launch.json” ein.

{
            "type": "java",
            "name": "Debug (test)",
            "request": "launch",
            "mainClass": "de.frickeldave.fleckerlteppich.telemetry.TelemetryApplication",
            "preLaunchTask": "startmariadb",
            "args": "--spring.profiles.active=test"
        },

Ich habe hier den Task, der zu starten ist “startmariadb” genannt. Nun legst du die Daten “tasks.json” im Verzeichnis “.vscode” an. In dieser definierst du, wie der task gestartet werden soll.

{
    "version": "2.0.0",
    "tasks": [
      {
         "label": "startmariadb",
         "type": "shell",
         "group": "none",
         "command": "docker-compose",
         "args": [
               "-f",
               "./telemetry/docker-compose-test.yml",
               "up",
               "-d"
            ],
         "detail": "Prelaunch script to start mariadb"
      }
    ]
 }

Das Start-argument ist “docker-compose”, die Argumente sind darunter als array gelistet. Im Gegensatz zum manuellen Aufruf zuvor, habe ich hier das Argument “-d” eingefügt, welches dafür sorgt, dass der Container unabhängig im Hintergrund startet.
Möchtest du nachkontrollieren, was ausgeführt wurde, musst du beachten, das VSCode die Ausgaben in 2 Fenster splittet. Eines für die Task-Aktion, eines in dem die Ausgaben der Java Spring Boot Anwendung angezeigt werden.

Stoppen von mariadb

Nun liegt es an Dir und deiner Applikation, ob du die Datenbank nach der Debug Session wieder automatisch beenden läßt. Hierfür stellt VSCode die Aktion “postDebugTask” in der “launch.json” zur Verfügung, an die du einen neuen Task binden kannst, der docker-compose mit den passenden Befehlen zum herunterfahren startet.

{
            "type": "java",
            "name": "Debug (test)",
            "request": "launch",
            "mainClass": "de.frickeldave.fleckerlteppich.telemetry.TelemetryApplication",
            "preLaunchTask": "startmariadb",
            "postDebugTask": "stopmariadb",
            "args": "--spring.profiles.active=test"
},

Wie zuvor legst du nun in der “tasks.json” einen neuen task an, mit dem der Container gestoppt wird.

{
        "label": "stopmariadb",
        "type": "shell",
        "group": "none",
        "command": "docker-compose",
        "args": [
              "-f",
              "./telemetry/docker-compose-test.yml",
              "down",
              "-v"
           ],
        "detail": "Prelaunch script to start mariadb"
}

An dieser Stelle kannst du natürlich beliebig spielen. Schau einfach unter “docker-compose down –help” nach, was für Möglichkeiten hier bestehen.

Eintragen der Datenbankkonfiguration

Nun fehlt als letzter Schritt noch das Eintragen der Datenbankverbindung in die zuvor erstellten Konfigurationsdateien. Dies erledigen wir in den folgenden Teilen dieser Artikelserie, in der wir erst eine simple Spring Boot Anwendung erstellen und im Anschluss diese um CRUD Operationen gegen die H2 und die mariadb Datenbanken erweitern.

Fazit

Du siehst, es ist nicht viel Arbeit, VSCode so zu konfigurieren, dass du ein Java Spring Boot Anwendung damit entwickeln kannst. Ich will hier keien direkten Vergleich zwischen Eclipse, IntelliJ und VSCode ziehen, letztendlich musst du dir hier dein eigenes Bild machen. Ich denke aber, dass der Invest for eine kommerzielle Entwickler-IDE nicht mehr unbedingt notwendig ist und viele Java Spring Boot Projekte mit VSCode umsetzbar sind.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.