Ćwiczenie — wdrażanie aplikacji Java EE (Jakarta EE) w aplikacji JBoss EAP w usłudze Azure App Service

Ukończone

W tym ćwiczeniu wdrożysz aplikację Java EE (Jakarta EE) w aplikacji JBoss EAP w usłudze Azure App Service. Wtyczka Maven służy do konfigurowania projektu, kompilowania i wdrażania aplikacji oraz konfigurowania źródła danych.

Konfigurowanie aplikacji za pomocą wtyczki Maven dla usługi Azure App Service

Skonfigurujmy aplikację, wykonując cel konfiguracji w wtyczce Maven dla usługi Azure App Service.

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

Ważny

Jeśli zmienisz region serwera MySQL, należy również zmienić go na ten sam region dla serwera aplikacji Java EE, aby zminimalizować opóźnienia.
W poleceniu wybierz Java 11 jako wersję Java i stos środowiska uruchomieniowego JBoss EAP 7.

Element wejściowy Wartość
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

Po uruchomieniu polecenia w terminalu będą wyświetlane komunikaty podobne do następujących:

$ ./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] ------------------------------------------------------------------------
$ 

Po zakończeniu polecenia zobaczysz, że następujący wpis zostanie dodany w pliku pom.xml narzędzia Maven.

  <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>

Ważny

Sprawdź element <region>. Jeśli nie jest to ta sama lokalizacja instalacji co MySQL, zmień ją na tę samą lokalizację.

Po dodaniu powyższej konfiguracji do wdrożenia na platformie Azure dodaj następujące wpisy XML, aby wdrożyć plik startowy. Zasób <type>startup</type> wdraża określony skrypt jako startup.sh (Linux) lub startup.cmd (Windows) w /home/site/scripts/. W poniższym kroku skonfigurujemy skrypt uruchamiania.

              <!-- 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 -->

Notatka

Możesz określić następujący zasób do wdrożenia w pliku XML:

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

    • type=war wdroży plik WAR do /home/site/wwwroot/app.war, jeśli path nie zostanie określony
    • type=war&path=webapps/<appname>\ będzie zachowywać się dokładnie tak jak wardeploy przez rozpakowywanie aplikacji do /home/site/wwwroot/webapps/<nazwa aplikacji>
    • type=jar wdroży plik wojenny w /home/site/wwwroot/app.jar. path parametr zostanie zignorowany
    • type=ear wdroży plik wojenny w /home/site/wwwroot/app.ear. path parametr zostanie zignorowany
    • type=lib wdroży plik jar w katalogu /home/site/libs. Parametr path musi być określony
    • type=static wdroży skrypt w /home/site/scripts. path parametr musi zostać określony
    • type=startup wdroży skrypt jako startup.sh (Linux) lub startup.cmd (Windows) w /home/site/scripts/. path parametr zostanie zignorowany
    • type=zip rozpakowuje plik zip do /home/site/wwwroot. parametr path jest opcjonalny.

Teraz sprawdź wartości nazwy grupy zasobów i nazwy aplikacji z powyższego pliku XML. Zanotuj te nazwy lub lepiej przypisz je do zmiennych środowiskowych.

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

Jeśli używasz Bash, skonfiguruj zmienne środowiskowe za pomocą następującego polecenia. Użyjesz tych wartości później.

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

Kompilowanie i budowanie aplikacji Java EE

Po skonfigurowaniu ustawień wdrażania usługi Azure App Service skompiluj i spakuj kod źródłowy.

./mvnw clean package

Następujące dane wyjściowe są wyświetlane w terminalu:

[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] ------------------------------------------------------------------------

Wdrażanie aplikacji Java EE w aplikacji JBoss EAP w usłudze Azure App Service

Po skompilowaniu i spakowaniu kodu wdróż aplikację:

./mvnw azure-webapp:deploy

W terminalu zostanie wyświetlony następujący komunikat:

[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] ------------------------------------------------------------------------

Zanotuj adres URL wdrożonej aplikacji, szczególnie następujący wiersz w danych wyjściowych narzędzia Maven:

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

Konfigurowanie połączenia z bazą danych

Przykładowa aplikacja łączy się z bazą danych MySQL i wyświetla dane.

W konfiguracji projektu Maven w pom.xmlokreślono sterownik MySQL JDBC w następujący sposób:

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

W związku z tym narzędzie JBoss EAP automatycznie instaluje sterownik JDBC do pakietu wdrożeniowego (ROOT.war). Możesz odwołać się do nazwy sterownika JDBC mySQL w następujący sposób:

ROOT.war_com.mysql.cj.jdbc.Driver_8_0

Tworzenie obiektu MySQL DataSource w aplikacji JBoss EAP

Aby uzyskać dostęp do usługi Azure Database for MySQL, należy skonfigurować obiekt DataSource w aplikacji JBoss EAP i określić nazwę JNDI w kodzie źródłowym.

Aby utworzyć obiekt DataSource MySQL w JBoss EAP, utworzyliśmy następujący skrypt startowy. Plik skryptu createMySQLDataSource.sh znajduje się w katalogu /WEB-INF.

Notatka

W skrypcie wiążemy źródło danych MySQL za pomocą komendy JBoss CLI. Parametry połączenia, nazwa użytkownika i hasło używają zmiennych środowiskowych MYSQL_CONNECTION_URL, MYSQL_USERi MYSQL_PASSWORD.

Źródło pliku skryptu jest wyświetlane w następnej kolejności. Ten plik skryptu został już przekazany do usługi App Service, ale nie został jeszcze skonfigurowany do wywołania.

#!/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

Teraz skonfiguruj wystąpienie usługi App Service w celu wywołania skryptu uruchamiania:

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

Po uruchomieniu skryptu będzie on wywoływany za każdym razem, gdy serwer aplikacji zostanie ponownie uruchomiony.

Notatka

Jeśli artefakt wdrożenia nie jest ROOT.war, musisz również zmienić wartość --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_8_0.

Konfigurowanie zmiennych środowiskowych na potrzeby nawiązywania połączenia z bazą danych MySQL

Po skonfigurowaniu skryptu uruchamiania skonfiguruj usługę App Service tak, aby korzystała z określonych zmiennych środowiskowych:

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

Napiwek

Wartości MYSQL_CONNECTION_URL, MYSQL_USER i MYSQL_PASSWORD zostały ustawione z poprzedniej jednostki.

Potwierdzanie odwołania do źródła danych w kodzie

Aby uzyskać dostęp do bazy danych MySQL z poziomu aplikacji, należy skonfigurować odwołanie do źródła danych w projekcie aplikacji. Zaimplementowaliśmy kod dostępu do bazy danych przy użyciu interfejsu API trwałości języka Java (JPA).

Konfiguracja odwołania DataSource została wprowadzona w pliku persistence.xml, który jest plikiem konfiguracji JPA.

Uzyskaj dostęp do następującego pliku:

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

Sprawdź, czy nazwa DataSource jest zgodna z nazwą używaną w konfiguracji. Kod utworzył już nazwę JNDI jako java:jboss/datasources/JPAWorldDataSource:

  <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>

Następnie możesz uzyskać dostęp do bazy danych MySQL, do której odwołuje się nazwa jednostki PersistenceContext w następujący sposób:

@Transactional(REQUIRED)
@RequestScoped
public class CityService {

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

Uzyskiwanie dostępu do aplikacji

W przykładowej aplikacji zaimplementowaliśmy trzy punkty końcowe REST. Możesz uzyskać dostęp do aplikacji i zweryfikować te punkty końcowe przy użyciu przeglądarki internetowej lub polecenia curl.

Aby uzyskać dostęp do aplikacji, musisz odwołać się do adresu URL aplikacji, który został uzyskany z wcześniejszej sekcji:

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

Uruchom następujące polecenie, aby uzyskać wszystkie informacje o kontynencie w formacie JSON.

Zrzut ekranu przedstawiający obszar jako punkt końcowy REST.

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

Jeśli określisz kontynent w adresie URL, możesz pobrać wszystkie kraje/regiony na określonym kontynencie.

Zrzut ekranu przedstawiający kontynent jako punkt końcowy REST.

$ 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"
}
....

Na koniec, jeśli po /countriesokreślisz kod kraju/regionu, możesz uzyskać wszystkie miasta, które mają populację większą niż 1 milion w kraju/regionie.

Zrzut ekranu przedstawiający miasta jako punkt końcowy REST.

$ 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"

Podsumowanie ćwiczenia

Sprawdzono teraz punkty końcowe REST aplikacji i przetestowano, czy aplikacja może pobierać dane z bazy danych MySQL.

W następnej lekcji zapoznasz się z dziennikami serwera.