Übung: Bereitstellen einer Java EE-Anwendung (Jakarta EE) für JBoss EAP auf Azure App Service

Abgeschlossen

In dieser Übung stellen Sie eine Java EE-Anwendung (Jakarta EE) für JBoss EAP in Azure App Service bereit. Sie verwenden das Maven-Plug-In, um das Projekt zu konfigurieren, die Anwendung zu kompilieren und bereitzustellen und eine Datenquelle zu konfigurieren.

Konfigurieren der App mit dem Maven-Plug-In für Azure App Service

Konfigurieren Sie die Anwendung, indem Sie das Konfigurationsziel im Maven-Plug-In für Azure App Service ausführen.

./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config

Wichtig

Wenn Sie die Region für Ihren MySQL-Server ändern, sollten Sie zur Minimierung wartezeitbedingter Verzögerungen auch mit Ihrem Java EE-Anwendungsserver in diese Region wechseln.
Wählen Sie im Befehl Java 11 als Java-Version und JBoss EAP 7 als Runtimestapel aus.

Eingabeelement Wert
Available subscriptions: Your appropriate subsctioption
Choose a Web Container Web App [\<create\>]: 1: <create>
Define value for OS [Linux]: Linux
Define value for javaVersion [Java 17]: 2: Java 11
Define value for runtimeStack: 1: Jbosseap 7
Define value for pricingTier [P1v3]: P1v3
Confirm (Y/N) [Y]: Y

Nachdem Sie den Befehl ausgeführt haben, werden im Terminal Meldungen ähnlich den folgenden angezeigt:

$ ./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------< com.microsoft.azure.samples:jakartaee-app-on-jboss >---------
[INFO] Building jakartaee-app-on-jboss 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO] 
[INFO] --- azure-webapp-maven-plugin:2.5.0:config (default-cli) @ jakartaee-app-on-jboss ---
[WARNING] The POM for com.microsoft.azure.applicationinsights.v2015_05_01:azure-mgmt-insights:jar:1.0.0-beta is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details
[INFO] Auth type: OAUTH2
Username: YOUR_EMAIL_ADDRESS@microsoft.com
Available subscriptions:
[INFO] Subscription: YOUR_SUBSCRIPTION(********-****-****-****-************)
[INFO] It may take a few minutes to load all Java Web Apps, please be patient.
Web Container Web Apps in subscription Microsoft Azure Internal Billing-CDA:
* 1: <create>
  2: jakartaee-app-on-jboss-yoshio (linux, jbosseap 7.2-java8)
Please choose a Web Container Web App [<create>]: 
Define value for OS [Linux]:
* 1: Linux
  2: Windows
  3: Docker
Enter your choice: 
Define value for javaVersion [Java 8]:
* 1: Java 8
  2: Java 11
Enter your choice: 
Define value for runtimeStack:
  1: Jbosseap 7.2
  2: Jbosseap 7
* 3: Tomcat 8.5
  4: Tomcat 9.0
Enter your choice: 1
Define value for pricingTier [P1v3]:
  1: P3v3
  2: P2v3
* 3: P1v3
Enter your choice: 
Please confirm webapp properties
Subscription Id : ********-****-****-****-************
AppName : jakartaee-app-on-jboss-1625038814881
ResourceGroup : jakartaee-app-on-jboss-1625038814881-rg
Region : westeurope
PricingTier : P1v3
OS : Linux
Java : Java 8
Web server stack: Jbosseap 7.2
Deploy to slot : false
Confirm (Y/N) [Y]: 
[INFO] Saving configuration to pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:43 min
[INFO] Finished at: 2021-06-30T16:40:47+09:00
[INFO] ------------------------------------------------------------------------
$ 

Nach Abschluss des Befehls sehen Sie, dass der folgende Eintrag in die Maven-Datei pom.xml eingefügt wurde.

  <build>
    <finalName>ROOT</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
      </plugin>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-webapp-maven-plugin</artifactId>
            <version>2.9.0</version>
            <configuration>
                <schemaVersion>v2</schemaVersion>
                <resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
                <appName>jakartaee-app-on-jboss-1625038814881</appName>
                <pricingTier>P1v3</pricingTier>
                <region>centralus</region>
                <runtime>
                    <os>Linux</os>
                    <javaVersion>Java 11</javaVersion>
                    <webContainer>Jbosseap 7</webContainer>
                </runtime>
                <deployment>
                    <resources>
                        <resource>
                            <directory>${project.basedir}/target</directory>
                            <includes>
                                <include>*.war</include>
                            </includes>
                        </resource>
                    </resources>
                </deployment>
            </configuration>
        </plugin>
    </plugins>
  </build>

Wichtig

Überprüfen Sie das <region>-Element. Wenn der Standort für die Installation nicht identisch mit dem für MySQL ist, ändern Sie ihn in denselben Standort.

Nachdem Sie die oben angegebene Konfiguration für die Bereitstellung in Azure hinzugefügt haben, fügen Sie die folgenden XML-Einträge hinzu, um die Startdatei bereitzustellen. Die Ressource <type>startup</type> stellt das angegebene Skript unter /home/site/scripts/ als startup.sh (Linux) oder startup.cmd (Windows) bereit. Das Startskript wird im nächsten Schritt konfiguriert.

              <!-- Please add following lines -->
              <resource>
                <type>startup</type>
                <directory>${project.basedir}/src/main/webapp/WEB-INF/</directory>
                <includes>
                  <include>createMySQLDataSource.sh</include>
                </includes>
              </resource>
              <!-- Please add following lines -->

Hinweis

Sie können die folgende Ressource für die Bereitstellung im XML-Code angeben:

  • type=<war|jar|ear|lib|startup|static|zip>

    • type=war stellt die WAR-Datei unter /home/site/wwwroot/app.war bereit, wenn pathnicht angegeben ist.
    • type=war&path=webapps/<appname>\ verhält sich genau wie „wardeploy“, und die App wird unter „/home/site/wwwroot/webapps/<appname>“ entzippt.
    • type=jar stellt die WAR-Datei unter /home/site/wwwroot/app.jar bereit. Der Parameter path wird ignoriert.
    • type=ear stellt die WAR-Datei unter /home/site/wwwroot/app.ear bereit. Der Parameter path wird ignoriert.
    • type=lib stellt die JAR-Datei unter „/home/site/libs“ bereit. Der Parameter path muss angegeben werden.
    • type=static stellt das Skript unter /home/site/scripts bereit. Der Parameter path muss angegeben werden.
    • type=startup stellt das Skript unter /home/site/scripts/ als startup.sh (Linux) oder startup.cmd (Windows) bereit. Der Parameter path wird ignoriert.
    • type=zip entzippt die ZIP-Datei unter /home/site/wwwroot. Der Parameter path ist optional.

Überprüfen Sie nun die Werte für den Namen der Ressourcengruppe und den Anwendungsnamen aus der obigen XML-Datei. Notieren Sie diese Namen, oder weisen Sie sie besser Umgebungsvariablen zu.

<resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
<appName>jakartaee-app-on-jboss-1625038814881</appName>

Wenn Sie Bash verwenden, konfigurieren Sie die Umgebungsvariablen mit dem folgenden Befehl. Sie verwenden diese Werte später.

export RESOURCEGROUP_NAME=jakartaee-app-on-jboss-1625038814881-rg
export WEBAPP_NAME=jakartaee-app-on-jboss-1625038814881

Kompilieren und Erstellen der Java EE-Anwendung

Nachdem Sie die Einstellungen für die Bereitstellung von Azure App Service konfiguriert haben, kompilieren und packen Sie den Quellcode.

./mvnw clean package

Die folgende Ausgabe wird im Terminal angezeigt:

[INFO] Packaging webapp
[INFO] Assembling webapp [jakartaee-app-on-jboss] in [/private/tmp/mslearn-jakarta-ee-azure/target/ROOT]
[INFO] Processing war project
[INFO] Copying webapp resources [/private/tmp/mslearn-jakarta-ee-azure/src/main/webapp]
[INFO] Webapp assembled in [369 msecs]
[INFO] Building war: /private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.656 s
[INFO] Finished at: 2023-03-04T12:35:43-05:00
[INFO] ------------------------------------------------------------------------

Bereitstellen der Java EE-App für JBoss EAP in Azure App Service

Nachdem Sie den Code kompiliert und gepackt haben, stellen Sie die Anwendung bereit:

./mvnw azure-webapp:deploy

Die folgende Meldung wird im Terminal angezeigt:

[INFO] Creating resource group jakartaee-app-on-jboss-1625038814881-rg in region westeurope...
[INFO] Successfully created resource group jakartaee-app-on-jboss-1625038814881-rg.
[INFO] Creating app service plan...
[INFO] Successfully created app service plan asp-jakartaee-app-on-jboss-1625038814881.
[INFO] Creating web app jakartaee-app-on-jboss-1625038814881...
[INFO] Successfully created Web App jakartaee-app-on-jboss-1625038814881.
[INFO] Trying to deploy artifact to jakartaee-app-on-jboss-1625038814881...
[INFO] Deploying (/private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war)[war]  ...
[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:11 min
[INFO] Finished at: 2023-03-04T12:38:39-05:00
[INFO] ------------------------------------------------------------------------

Notieren Sie sich die URL der bereitgestellten Anwendung, insbesondere folgende Zeile in der Maven-Ausgabe:

[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net

Konfigurieren einer Datenbankverbindung

Die Beispielanwendung stellt eine Verbindung mit der MySQL-Datenbank her und zeigt Daten an.

In der Konfiguration des Maven-Projekts in pom.xml wurde der JDBC-Treiber für MySQL wie folgt angegeben:

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql-jdbc-driver}</version>
    </dependency>

Daher wird der JDBC-Treiber von JBoss EAP automatisch im Bereitstellungspaket ROOT.war installiert. Sie können den Namen des JDBC-Treibers für MySQL wie folgt angeben:

ROOT.war_com.mysql.cj.jdbc.Driver_8_0

Erstellen des MySQL-Objekts „DataSource“ in JBoss EAP

Für den Zugriff auf die Azure Database for MySQL-Instanz müssen Sie das DataSource-Objekt in JBoss EAP konfigurieren und im Quellcode den JNDI-Namen angeben.

Zum Erstellen eines DataSource-MySQL-Objekts in JBoss EAP wurde die folgende Shellskriptdatei für den Start erstellt. Bei der Skriptdatei handelt es sich um createMySQLDataSource.sh, und sie befindet sich im /WEB-INF-Verzeichnis.

Hinweis

Im Skript binden Sie das DataSource-MySQL-Objekt mithilfe eines JBoss-CLI-Befehls. Für Verbindungszeichenfolge, Benutzername und Kennwort werden die Umgebungsvariablen MYSQL_CONNECTION_URL, MYSQL_USER und MYSQL_PASSWORD verwendet.

Die Quelle der Skriptdatei wird als Nächstes gezeigt. Diese Skriptdatei wurde bereits in App Service hochgeladen, aber noch nicht für den Aufruf konfiguriert.

#!/usr/bin/bash

# In order to use the variables in JBoss CLI scripts
# https://access.redhat.com/solutions/321513
#
sed -i -e "s|.*<resolve-parameter-values.*|<resolve-parameter-values>true</resolve-parameter-values>|g" /opt/eap/bin/jboss-cli.xml

/opt/eap/bin/jboss-cli.sh --connect <<EOF
data-source add --name=JPAWorldDataSourceDS \
--jndi-name=java:jboss/datasources/JPAWorldDataSource \
--connection-url=${MYSQL_CONNECTION_URL} \
--driver-name=ROOT.war_com.mysql.cj.jdbc.Driver_8_0 \
--user-name=${MYSQL_USER} \
--password=${MYSQL_PASSWORD} \
--min-pool-size=5 \
--max-pool-size=20 \
--blocking-timeout-wait-millis=5000 \
--enabled=true \
--driver-class=com.mysql.cj.jdbc.Driver \
--jta=true \
--use-java-context=true \
--valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker \
--exception-sorter-class-name=com.mysql.cj.jdbc.integration.jboss.ExtendedMysqlExceptionSorter
exit
EOF

Konfigurieren Sie als Nächstes die App Service-Instanz zum Aufrufen des Startskripts:

az webapp config set --startup-file '/home/site/scripts/startup.sh' \
-n ${WEBAPP_NAME} \
-g ${RESOURCEGROUP_NAME}

Nachdem das Skript ausgeführt wurde, wird es jedes Mal aufgerufen, wenn der Anwendungsserver neu gestartet wird.

Hinweis

Wenn es sich bei Ihrem Bereitstellungsartefakt nicht um ROOT.war handelt, müssen Sie den --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_8_0-Wert auch ändern.

Konfigurieren der Umgebungsvariablen zum Herstellen einer Verbindung mit MySQL

Nachdem Sie das Startskript konfiguriert haben, konfigurieren Sie die App Service-Instanz für die Verwendung bestimmter Umgebungsvariablen:

az webapp config appsettings set \
  --resource-group ${RESOURCEGROUP_NAME} --name ${WEBAPP_NAME} \
  --settings \
  MYSQL_CONNECTION_URL='jdbc:mysql://mysqlserver-**********.mysql.database.azure.com:3306/world?useSSL=true&requireSSL=false' \
  MYSQL_PASSWORD='************' \
  MYSQL_USER=azureuser

Tipp

Die Werte von MYSQL_CONNECTION_URL, MYSQL_USER und MYSQL_PASSWORD wurden in der vorherigen Lerneinheit festgelegt.

Überprüfen des Verweises auf das DataSource-Objekt im Code.

Für den Zugriff auf die MySQL Database-Instanz über die Anwendung müssen Sie den Datenquellenverweis im Anwendungsprojekt konfigurieren. Der Zugriffscode für die Datenbank wurde mithilfe der Java Persistence API (JPA) implementiert.

Die Konfiguration für den Verweis auf das DataSource-Objekt wurde in persistence.xml hinzugefügt. Hierbei handelt es sich um die Konfigurationsdatei der JPA.

Rufen Sie folgende Datei auf:

├── src
│   ├── main
│   │   ├── resources
│   │   │   └── META-INF
│   │   │       └── persistence.xml

Überprüfen Sie, ob der Name des DataSource-Objekts mit dem in der Konfiguration verwendeten Namen übereinstimmt. Der Code hat den JNDI-Namen bereits auf java:jboss/datasources/JPAWorldDataSource festgelegt:

  <persistence-unit name="JPAWorldDatasourcePU" transaction-type="JTA">
    <jta-data-source>java:jboss/datasources/JPAWorldDataSource</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.generate_statistics" value="true" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
  </persistence-unit>
</persistence>

Anschließend können Sie auf die MySQL Database-Instanz, auf die im Namen der Einheit PersistenceContext verwiesen wird, wie folgt zugreifen:

@Transactional(REQUIRED)
@RequestScoped
public class CityService {

    @PersistenceContext(unitName = "JPAWorldDatasourcePU")
    EntityManager em;

Zugreifen auf die Anwendung

In der Beispielanwendung wurden drei REST-Endpunkte implementiert. Sie können über einen Webbrowser oder mit einem curl-Befehl auf die Anwendung zugreifen und diese Endpunkte überprüfen.

Wenn Sie auf die Anwendung zugreifen möchten, müssen Sie auf die Anwendungs-URL verweisen, die Sie in einem vorherigen Abschnitt abgerufen haben:

[INFO] Successfully deployed the artifact to  
https://jakartaee-app-on-jboss-1606464084546.azurewebsites.net

Führen Sie den folgenden Befehl aus, um alle Kontinentinformationen im JSON-Format abzurufen.

Screenshot that shows area as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area
["North America","Asia","Africa","Europe","South America","Oceania","Antarctica"]$ 

Wenn Sie den Kontinent in der URL angeben, können Sie alle Länder/Regionen des angegebenen Kontinents abrufen.

Screenshot that shows continent as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/area/Asia | jq '.[] | { name: .name, code: .code }'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100 16189  100 16189    0     0  65278      0 --:--:-- --:--:-- --:--:-- 65542
{
  "name": "Afghanistan",
  "code": "AFG"
}
{
  "name": "United Arab Emirates",
  "code": "ARE"
}
{
  "name": "Armenia",
  "code": "ARM"
}
{
  "name": "Azerbaijan",
  "code": "AZE"
}
{
  "name": "Bangladesh",
  "code": "BGD"
}
....

Wenn Sie schließlich nach /countries einen Länder-/Regionscode angeben, können Sie alle Städte mit mehr als einer Million Einwohnern im jeweiligen Land oder der Region abrufen.

Screenshot that shows cities as the REST endpoint.

$ curl https://${WEBAPP_NAME}.azurewebsites.net/countries/JPN | jq '.[].name'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   100   788  100   788    0     0   2671      0 --:--:-- --:--:-- --:--:--  2662
"Tokyo"
"Jokohama [Yokohama]"
"Osaka"
"Nagoya"
"Sapporo"
"Kioto"
"Kobe"
"Fukuoka"
"Kawasaki"
"Hiroshima"
"Kitakyushu"

Zusammenfassung der Übung

Sie haben die REST-Endpunkte der Anwendung überprüft und getestet, ob die Anwendung Daten von der MySQL Database-Instanz abrufen kann.

In der nächsten Lerneinheit untersuchen Sie die Serverprotokolle.