[DOCKER] Serverloses Java EE beginnend mit Quarkus und Cloud Run

Einführung

Cloud Run wurde neulich in Google Cloud Next 19 veröffentlicht. Dies ist Googles vollständig verwaltetes GCP-Angebot Knative, mit dem HTTP-gestartete Docker-Container auf k8s automatisch skaliert werden. AWS Fargate, Heroku oder wir Haben Sie die GAE Flexible Environment gesagt, die Sie wirklich wollten?

Dieses Mal werde ich eine Hochgeschwindigkeits-Serverless-Java-EE-Anwendung mit Quarkus erstellen, einem Java-EE-Container, der Super-Sound-Geschwindigkeit / Super-Leichtgewicht singt und Java mit Graal zu einer Binärdatei kompilieren kann. .. Lass mich nicht sagen ** "Spin-up ist langsam, weil es Java ist" **!

TL;DR

-Klonen Sie dieses Produkt

Entwickeln Sie eine Beispielanwendung mit Quarkus

What is Quarkus?

Quarkus ist ein Java EE-Container der nächsten Generation, der von Redhat erstellt wurde. Er verfügt über die Funktion "Supersonic Subatomic Java" und startet mit einer anderen Dimensionsgeschwindigkeit von ** 10 ms **, die von anderen nicht erreicht wird. Ich werde. Die Hauptmerkmale sind wie folgt.

Die Details sind länger geworden, deshalb habe ich sie in einem separaten Artikel zusammengefasst. Wenn Sie interessiert sind, lesen Sie dies bitte auch. "Blog Was ist das: Java EE-Container in der Ära ohne Server - Quarkus"

Beispiel-App-Spezifikationen

Jetzt erstellen wir eine Beispielanwendung. Alles ist in Ordnung, aber dieses Mal werde ich versuchen, "** Bank API **" zu machen.

Die Funktionen sind wie folgt.

Jeder kann einzahlen und abheben, da die Benutzerverwaltung zur Vereinfachung nicht durchgeführt wird. Wir werden auch die Kontoinformationen in der Datenbank speichern.

Ein Projekt erstellen

Projekte können mit Maven oder Gradle erstellt werden. Dieses Mal werde ich Maven verwenden.

% mvn io.quarkus:quarkus-maven-plugin:create
...
Set the project groupId [org.acme.quarkus.sample]: cn.orz.pascal.mybank
Set the project artifactId [my-quarkus-project]: my-bank
Set the project version [1.0-SNAPSHOT]: 
Do you want to create a REST resource? (y/n) [no]: y
Set the resource classname [cn.orz.pascal.mybank.HelloResource]: 
Set the resource path  [/hello]: 
...
[INFO] Finished at: 2019-04-14T17:51:48-07:00
[INFO] ------------------------------------------------------------------------

/ Hallo als Beispielendpunkt hinzugefügt. Der Code für JAX-RS lautet wie folgt.

@Path("/hello")
public class HelloResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}

Es ist ein normaler JAX-RS-Code. Lass es uns laufen. Starten Sie im Entwicklungsmodus.

$ mvn compile quarkus:dev
...
2019-04-14 17:52:13,685 INFO  [io.quarkus](main) Quarkus 0.13.1 started in 2.042s. Listening on: http://[::]:8080
2019-04-14 17:52:13,686 INFO  [io.quarkus](main) Installed features: [cdi, resteasy]

Ich werde versuchen, mit Locken darauf zuzugreifen.

$ curl http://localhost:8080/hello
hello 

Sie haben den Zugriff erfolgreich bestätigt.

Vorbereitung der DB-Umgebung

Erstellen Sie als Nächstes eine Kontotabelle, die Ihr Konto darstellt. Zunächst muss die Datenbank vorbereitet werden. Starten Sie also postgres mit Docker.

$ docker run -it -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword postgres        
...
2019-04-15 01:29:51.370 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2019-04-15 01:29:51.370 UTC [1] LOG:  listening on IPv6 address "::", port 5432
2019-04-15 01:29:51.374 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2019-04-15 01:29:51.394 UTC [50] LOG:  database system was shut down at 2019-04-15 01:29:51 UTC
2019-04-15 01:29:51.404 UTC [1] LOG:  database system is ready to accept connections

JPA-Einstellungen

Richten Sie als Nächstes JPA ein. Fügen Sie zunächst eine Abhängigkeit hinzu.

#Bestätigung des Nebenstellennamens
$ mvn quarkus:list-extensions|grep jdbc         
[INFO] 	 * JDBC Driver - H2 (io.quarkus:quarkus-jdbc-h2)
[INFO] 	 * JDBC Driver - MariaDB (io.quarkus:quarkus-jdbc-mariadb)
[INFO] 	 * JDBC Driver - PostgreSQL (io.quarkus:quarkus-jdbc-postgresql)
$ mvn quarkus:list-extensions|grep hibernate
[INFO] 	 * Hibernate ORM (io.quarkus:quarkus-hibernate-orm)
[INFO] 	 * Hibernate ORM with Panache (io.quarkus:quarkus-hibernate-orm-panache)
[INFO] 	 * Hibernate Validator (io.quarkus:quarkus-hibernate-validator)
#Erweiterung hinzufügen
$ mvn quarkus:add-extension -Dextensions="io.quarkus:quarkus-jdbc-postgresql"
$ mvn quarkus:add-extension -Dextensions="io.quarkus:quarkus-hibernate-orm"

Beschreiben Sie als Nächstes die DB-Einstellungen in "src / main / resources / application.properties". Grundsätzlich empfiehlt Quarkus, dass Sie alles in dieser application.properties auflisten, ohne eine separate Konfigurationsdatei wie persistance.xml oder log4j.xml zu definieren. Da für diese Datei auch microprofile-config verwendet wird, kann sie mit Umgebungsvariablen und Argumenten überschrieben werden. Mit anderen Worten, der Unterschied zwischen der Entwicklungsumgebung und STG oder Prod kann auf der Yaml-Seite von k8s definiert werden, sodass keine Erstellungsmethode wie das Umschalten der Einstellungen in Profile für jede Umgebung erforderlich ist und die Bedienung vereinfacht werden kann.

Dies passt hervorragend zu Umgebungen, die Twelve-Factor erfüllen, wie Dokcer, Cloud Run oder Heroku, in denen Umgebungsvariablen beim Start / bei der Bereitstellung angegeben werden. ..

Klicken Sie hier, um die Einstellungen anzuzeigen, die zu "application.properties" hinzugefügt werden sollen. Wie Sie sehen können, handelt es sich um eine DB-Einstellung.

# datasource account
quarkus.datasource.url: jdbc:postgresql://localhost:5432/postgres
quarkus.datasource.driver: org.postgresql.Driver
quarkus.datasource.username: postgres
quarkus.datasource.password: mysecretpassword

# database optional
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql: true

Fügen Sie Entität / Service / Ressource für die Kontoerstellung hinzu

Erstellen Sie als Nächstes eine Entität und einen Dienst von "Konto", die dem Konto entsprechen. Erstens Entität. Natürlich ist es normalerweise eine JPA-Einheit. Als persönliches Hobby verwendet PK UUID, es ist jedoch möglich, problemlos eine separate Sequenz zu verwenden.

@Entity
public class Account implements Serializable {
    private UUID id;
    private Long amount;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public UUID getId() {
        return id;
    }
    public void setId(UUID id) {
        this.id = id;
    }
    public Long getAmount() {
        return amount;
    }
    public void setAmount(Long amount) {
        this.amount = amount;
    }
}

Als nächstes folgt der Dienst, der die Entität betreibt.

@ApplicationScoped
public class AccountService {
    @Inject
    EntityManager em;

    @Transactional
    public void create(long amount) {
        Account account = new Account();
        account.setAmount(amount);
        em.persist(account);
    }
}

Schließlich ist es eine Ressource, die JAX-RS beschreibt.

@Path("/account")
public class AccountResource {
    @Inject
    AccountService accountService;

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/create")
    public void create() {
        accountService.create(0);
    }
}

Drücken wir / account / create.

$ curl -i -X POST -H "Content-Type: application/json" http://localhost:8080/account/create
HTTP/1.1 204 No Content
Date: Mon, 15 Apr 2019 02:56:30 GMT

Es endete normal. Ich denke auch, dass die SQL, die wie folgt ausgeführt wird, in der Standardausgabe des Servers erscheint. Da "quarkus.hibernate-orm.log.sql" auf "true" gesetzt ist, können Sie das SQL-Protokoll überprüfen. Vergessen Sie nicht, es in der Produktion auf "false" zu setzen.

Hibernate: 
    insert 
    into
        Account
        (amount, id) 
    values
        (?, ?)

Fügen Sie eine API zum Erstellen des restlichen Kontos hinzu

Fügen wir die knusprigen und verbleibenden APIs hinzu. Fügen Sie AccountService.java Listen- und Einzahlungs- / Auszahlungsfunktionen hinzu.

@ApplicationScoped
public class AccountService {

    @Inject
    EntityManager em;

    @Transactional
    public void create(long amount) {
        Account account = new Account();
        account.setAmount(amount);
        em.persist(account);
    }

    @Transactional
    public List<Account> findAll() {
        return em.createQuery("SELECT a FROM Account a", Account.class)
                .setMaxResults(3)
                .getResultList();
    }

    @Transactional
    public Account deposit(UUID id, long amount) {
        em.createQuery("UPDATE Account SET amount = amount + :amount WHERE id=:id")
                .setParameter("id", id)
                .setParameter("amount", amount)
                .executeUpdate();
        return em.createQuery("SELECT a FROM Account a WHERE id=:id", Account.class)
                .setParameter("id", id)
                .getSingleResult();
    }

    @Transactional
    public Account withdraw(UUID id, long amount) {
        em.createQuery("UPDATE Account SET amount = amount - :amount WHERE id=:id")
                .setParameter("id", id)
                .setParameter("amount", amount)
                .executeUpdate();
        return em.createQuery("SELECT a FROM Account a WHERE id=:id", Account.class)
                .setParameter("id", id)
                .getSingleResult();
    }
}

Ändern Sie dann "AccountResource.java" wie folgt.

@Path("/account")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AccountResource {

    @Inject
    AccountService accountService;

    @POST
    public void create() {
        accountService.create(0);
    }

    @GET
    public List<Account> list() {
        return accountService.findAll();
    }

    @POST
    @Path("/deposit/{id}/{amount}")
    public Account deposit(@PathParam("id") UUID id, @PathParam("amount") long amount) {
        System.out.println(id + ":" + amount);
        return accountService.deposit(id, amount);
    }

    @POST
    @Path("/withdraw/{id}/{amount}")
    public Account withdraw(@PathParam("id") UUID id, @PathParam("amount") long amount) {
        System.out.println(id + ":" + amount);
        return accountService.withdraw(id, amount);
    }
}

Ich werde es versuchen.

$ curl -X POST -H "Content-Type: application/json" http://localhost:8080/account
$ curl -X GET -H "Content-Type: application/json" http://localhost:8080/account 
[{"amount":0,"id":"0687662d-5ac7-4951-bb11-c9ced6558a40"}]                                               
$ curl -X POST -H "Content-Type: application/json" http://localhost:8080/account/deposit/0687662d-5ac7-4951-bb11-c9ced6558a40/100 
{"amount":100,"id":"0687662d-5ac7-4951-bb11-c9ced6558a40"}                                              
$ curl -X POST -H "Content-Type: application/json" http://localhost:8080/account/deposit/0687662d-5ac7-4951-bb11-c9ced6558a40/100
{"amount":200,"id":"0687662d-5ac7-4951-bb11-c9ced6558a40"}                                                 
$ curl -X POST -H "Content-Type: application/json" http://localhost:8080/account/deposit/0687662d-5ac7-4951-bb11-c9ced6558a40/100
{"amount":300,"id":"0687662d-5ac7-4951-bb11-c9ced6558a40"}                                                  
$ curl -X POST -H "Content-Type: application/json" http://localhost:8080/account/withdraw/0687662d-5ac7-4951-bb11-c9ced6558a40/200
{"amount":100,"id":"0687662d-5ac7-4951-bb11-c9ced6558a40"} 

Ich konnte die Ein- / Auszahlungsfunktion erfolgreich implementieren.

Dokumentation

Nachdem die App-Funktion abgeschlossen ist, ist der nächste Schritt die Dokumentation. Quarkus unterstützt jedoch Open API und Swagger UI, sodass dies schnell erledigt werden kann.

Fügen Sie zunächst die Erweiterung hinzu.

$ mvn quarkus:list-extensions|grep openapi
[INFO] 	 * SmallRye OpenAPI (io.quarkus:quarkus-smallrye-openapi)
$ mvn quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-openapi"

Führen Sie nach dem Hinzufügen der Erweiterung "quarkus: dev" erneut aus. Gehen Sie dann zu http: // localhost: 8080 / openapi. Anschließend können Sie die OpenAPI-Definitionsdatei wie unten gezeigt aus JAX-RS generieren.

openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  /account:
    get:
      responses:
        200:
          description: OK
          content:
            application/json: {}
    post:
...

Sie können auch auf die folgenden Dokumente der Swagger-Benutzeroberfläche zugreifen, indem Sie auf "http: // localhost: 8080 / swagger-ui /" zugreifen. 004.png

In Cloud Run bereitstellen

Nachdem Quarkus eine explosive Java EE-App erstellt hat, stellen wir sie in der Umgebung ohne Server [Cloud Run] bereit (https://cloud.google.com/run/docs/). Wie ich zu Beginn schrieb, ist Cloud Run eine GCP-basierte CaaS-Umgebung (Containers as a Service), die auf Knative basiert. Es gibt eine Methode zur Bereitstellung in Ihrer eigenen GKE-Umgebung und eine komfortable, vollständig verwaltete GCP-Umgebung. Diesmal verwenden wir jedoch letztere.

Cloud SQL erstellen

Da wir diesmal PostgreSQL verwenden, wird RDB auch für GCP benötigt. Aus diesem Grund verwenden wir Cloud SQL, um eine verwaltete Datenbank zu erstellen.

$ gcloud sql instances create myinstance --region us-central1 --cpu=2 --memory=7680MiB --database-version=POSTGRES_9_6
$ gcloud sql users set-password postgres --instance=myinstance --prompt-for-password

Sie haben jetzt eine Datenbank mit dem Namen "Meine Instanz" erstellt. Sie können den Vorgang mit "gcloud sql instance list" überprüfen.

$ gcloud sql instances list
NAME        DATABASE_VERSION  LOCATION       TIER              PRIMARY_ADDRESS  PRIVATE_ADDRESS  STATUS
myinstance  POSTGRES_9_6      us-central1-b  db-custom-2-7680  xxx.xxx.xxx.xxx   -                RUNNABLE

Erstellen eines Docker-Images für Cloud Run

Erstellen Sie als Nächstes ein Docker-Image für Cloud Run. Ursprünglich sind keine speziellen Einstellungen für "Cloud Run" erforderlich. Bilder, die mit einem der im Quarkus-Projekt enthaltenen src / main / docker / Dockerfile.native | jvm erstellt wurden, funktionieren unverändert. GCP-verwalteter Cloud Run kann jedoch nicht in einer VPC platziert werden (Cloud Run auf GKE ist möglich). Daher basiert die Verbindung von Cloud Run zu Cloud SQL auf "Cloud SQL Proxy", anstatt eine direkte Verbindung mit ACL herzustellen.

Erstellen Sie ein Endpunktskript

Erstellen Sie ein Skript "src / main / script / run.sh", in dem sowohl die Proxy- als auch die Quarkus-App ausgeführt werden, z.

#!/bin/sh

# Start the proxy
/usr/local/bin/cloud_sql_proxy -instances=$CLOUDSQL_INSTANCE=tcp:5432 -credential_file=$CLOUDSQL_CREDENTIALS &

# wait for the proxy to spin up
sleep 10

# Start the server
./application -Dquarkus.http.host=0.0.0.0 -Dquarkus.http.port=$PORT

Das Starten von Proxy dauert einige Zeit, daher habe ich den Ruhezustand für etwa 10 Sekunden eingestellt. Offensichtlich dauert das Drehen mindestens 10 Sekunden, also möchte ich etwas dagegen tun ...

Erstellen und Erstellen einer Docker-Datei

Erstellen Sie als Nächstes eine Docker-Datei. Die Grundlagen sind die gleichen wie bei Dockerfile.native, erstellen Sie jedoch "src / main / docker / Dockerfile.gcp", einschließlich "run.sh" und "cloud_sql_proxy".

FROM registry.fedoraproject.org/fedora-minimal
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work

ADD https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 /usr/local/bin/cloud_sql_proxy
RUN chmod +x /usr/local/bin/cloud_sql_proxy
COPY src/main/script/run.sh /work/run.sh
RUN chmod +x /work/run.sh

EXPOSE $PORT
CMD ["./run.sh"]

Fügen Sie dann Dockerfile.gcp zu .dockerignore hinzu. Im Quarkus-Projekt werden zum Zeitpunkt der Erstellung nur bestimmte Dateien ausgeblendet. Wenn Sie diese also nicht ändern, tritt ein Fehler auf, da beim Docker-Build keine Zieldatei vorhanden ist. Die Reparaturunterschiede sind wie folgt.

$ diff .dockerignore.bak .dockerignore
4a5
> !src/main/script/run.s

Jetzt, wo wir fertig sind, bauen wir. In der vollständig verwalteten Version von "Cloud Run" muss sich das Bereitstellungsziel anscheinend in der Cloud-Registrierung befinden. Setzen Sie das Tag daher auf "gcr.io/project name / image name".

$ export PRJ_NAME="Projektname hier"
$ ./mvnw clean package -Pnative -DskipTests=true -Dnative-image.container-runtime=docker
$ docker build -f src/main/docker/Dockerfile.gcp -t gcr.io/${PRJ_NAME}/mybank .

Der native Image-Build von GraalVM ist sehr umfangreich, da er nach Abhängigkeiten sucht und in ein natives Image konvertiert. Es dauert 5 bis 10 Minuten, also genießen Sie bitte Ihre nostalgische Kaffeezeit.

Lokale Betriebsprüfung

Um den Vorgang lokal zu überprüfen, erstellen Sie ein Konto, das über "IAM and Management" auf den SQL-Client zugreifen kann, und erstellen Sie einen JSON-Formatschlüssel. Platzieren Sie dies an einem geeigneten lokalen Speicherort mit dem Namen "credentials.json", platzieren Sie es an einer sichtbaren Stelle auf dem Volume und geben Sie den Dateipfad in der Umgebungsvariablen "CLOUDSQL_CREDENTIALS" an, um den Vorgang lokal zu überprüfen. Ich werde.

$ export SQL_CONNECTION_NAME=$(gcloud sql instances describe myinstance|grep connectionName|cut -d" " -f2)
$ docker run -it -p 8080:8080 -v `pwd`:/key/ \
-e CLOUDSQL_INSTANCE=${SQL_CONNECTION_NAME} \
-e CLOUDSQL_CREDENTIALS=/key/credentials.json \
-e QUARKUS_DATASOURCE_URL=jdbc:postgresql://localhost:5432/postgres \
-e QUARKUS_DATASOURCE_PASSWORD="Passwort hier" \
gcr.io/${PRJ_NAME}/mybank

Fügen Sie dem Cloud Run-Dienstkonto SQL-Clientberechtigungen hinzu

Nachdem wir den Vorgang lokal bestätigt haben, werden wir Einstellungen für "Cloud Run" vornehmen. Wenn Sie die Schlüsseldatei in den Container einfügen, funktioniert sie wie oben beschrieben, ist jedoch in Bezug auf die Sicherheit schwierig. Daher muss SQL für das Dienstkonto "Google Cloud Run Service Agent ([email protected])" von Cloud Run verwendet werden Fügen Sie Client-Berechtigungen hinzu.

Geben Sie unter "IAM und Verwaltung" -> "IAM" den oben genannten Cloud Run Service Agent an und fügen Sie die Rolle "Cloud SQL Client" hinzu. Sie können jetzt von Cloud Run aus eine Verbindung ohne Schlüsseldatei herstellen.

Bereitstellung für Cloud Run

Jetzt ist es Zeit für die Bereitstellung in Cloud Run. Übertragen Sie zunächst das zuvor erstellte Image in die Cloud-Registrierung.

docker push gcr.io/${PRJ_NAME}/mybank

Dann bereitstellen.

$ export SQL_CONNECTION_NAME=$(gcloud sql instances describe myinstance|grep connectionName|cut -d" " -f2)
$ gcloud beta run deploy mybank \ 
--image gcr.io/${PRJ_NAME}/mybank \
--set-env-vars \
QUARKUS_DATASOURCE_URL=jdbc:postgresql://localhost:5432/postgres,\
QUARKUS_DATASOURCE_PASSWORD={DB-Passwort},\
CLOUDSQL_INSTANCE=$SQL_CONNECTION_NAME

Sie können Umgebungsvariablen mit "set-env-vars" angeben. Es ist praktisch, die Protokollstufe und die DB-Einstellungen nach Bedarf ändern zu können, ohne das Modul zu ändern.

$ gcloud beta run services list
   SERVICE         REGION       LATEST REVISION     SERVING REVISION    LAST DEPLOYED BY    LAST DEPLOYED AT
✔  mybank          us-central1  mybank-00017        mybank-00017        [email protected]      2019-04-25T08:50:28.872Z

Sie können sehen, dass es bereitgestellt wurde. Lassen Sie uns die URL des Verbindungsziels überprüfen.

$ gcloud beta run services describe mybank|grep hostname
hostname: https://mybank-xxx-uc.a.run.app

Lassen Sie uns die Operation mit Curl überprüfen.

[$ curl -X POST -H "Content-Type: application/json" https://mybank-xxx-uc.a.run.app/account
$ curl https://mybank-xxx-uc.a.run.app/account
[{"amount":0,"id":"b9efbb84-3b4d-4152-be6b-2cc68bfcbe71"}]

Das erste Hochfahren dauert ungefähr 10 Sekunden, aber danach können Sie sehen, dass es in ungefähr mehreren hundert ms arbeitet. DB-Zugang ist perfekt!

Zusammenfassung

Ich habe mit Quarkus und Cloud Run eine serverlose Java EE-Umgebung erstellt. GAE sperrt sich ein und Java EE dreht sich nicht. Wie wäre es also mit einem Produkt, das sich genau richtig anfühlt?

Ist es nicht interessant, mit ms order zu beginnen, während Sie den bekannten Java EE-Schreibstil wie JAX-RS / CDI und JPA schreiben? Diese Funktion passt sehr gut zur serverlosen Architektur "Starten eines Prozesses bei jeder Anforderung". Es scheint seltsam, zu Fast CGI zurückzukehren, aber ich denke, es ist eine interessante Funktion, dass GC, das mich mit Java stört, keine große Wirkung hat, da es im Prinzip lange Zeit nicht funktioniert.

Beide sind neu und instabil, und da es sich um Durchbrüche handelt, müssen wir uns überlegen, was wir mit den betrieblichen Aspekten tun sollen, aber ich möchte sie auch in Zukunft weiter verfolgen. Wenn Sie in der DB nichts unternehmen, funktioniert dies zunächst in der Reihenfolge ms, aber der Spin-up ist aufgrund der DB-Verbindung sehr umfangreich ...

Dann viel Spaß beim Hacken!

Referenz

Recommended Posts

Serverloses Java EE beginnend mit Quarkus und Cloud Run
Kommen Sie mit Java-Containern in Cloud Run zurecht
Führen Sie Batch mit Docker-Compose mit Java-Batch aus
Aktivieren Sie Java EE mit NetBeans 9
Führen Sie Java VM mit Web Assembly aus
Führen Sie die Java EE-Anwendung unter CICS aus
Verwenden Sie Java mit MSYS und Cygwin
Verteilte Ablaufverfolgung mit OpenCensus und Java
[Java EE] Implementieren Sie den Client mit WebSocket
Verwenden Sie JDBC mit Java und Scala.
Führen Sie logstash mit Docker aus und versuchen Sie, Daten in Elastic Cloud hochzuladen
Verwenden Sie Java 11 mit Google Cloud-Funktionen
PDF und TIFF mit Java 8 ausgeben
Microservices mit Docker- und Cloud-Leistung
Führen Sie in Java8 geschriebene Anwendungen in Java6 aus
Mit Java verschlüsseln und mit C # entschlüsseln
Java für Anfänger, Variablen und Typen
Überwachen Sie Java-Anwendungen mit Jolokia und Hawtio
One-JAR Java EE-Anwendung mit WebSphere Liberty
Verknüpfen Sie Java- und C ++ - Code mit SWIG
Probieren wir WebSocket mit Java und Javascript aus!
[Java] Lesen und Schreiben von Dateien mit OpenCSV
Einführung in Java ab 0 Teil 1
AWS Lambda (Lambda) Teil 1 mit Java startet jetzt
Java-Entwicklung mit Codenvy: Hello World! Run
Erstellen Sie Java-Anwendungen mit IBM Cloud-Funktionen
Erstellen Sie eine ARM-CPU-Umgebung mit qemu auf dem Mac und führen Sie Java aus [Ergebnis → Fehler]
Seien Sie vorsichtig mit Anfragen und Antworten, wenn Sie das Serverless Framework mit Java verwenden
Führen Sie Rust von Java mit JNA (Java Native Access) aus.
Erstellen und testen Sie Java + Gradle-Anwendungen mit Wercker
Versuchen Sie, Ruby und Java in Dapr zu integrieren
JSON mit Java und Jackson Teil 2 XSS-Maßnahmen
Erstellen Sie eine E2E-Testumgebung mit Selenium (Java).
Erstellen Sie mit Gradle mit VSCode Java → Ausführen
Erstellen Sie mit Docker ein Jupyter-Notizbuch und führen Sie Ruby aus
Kompilieren Sie Java und führen Sie es in der Befehlszeile aus
Bereiten Sie eine Scraping-Umgebung mit Docker und Java vor
KMS) Umschlagverschlüsselung mit OpenSL- und Java-Entschlüsselung
Java beginnend mit JShell-A Einblick in die Java-Welt
[Java] Konvertieren und Importieren von Dateiwerten mit OpenCSV
[Review] Lesen und Schreiben von Dateien mit Java (JDK6)