Ejercicio: Implementación de una aplicación de Java EE (Jakarta EE) en JBoss EAP en Azure App Service
En este ejercicio, implementará una aplicación de Java EE (Jakarta EE) en JBoss EAP en Azure App Service. Usará el complemento Maven para configurar el proyecto, compilar e implementar la aplicación, y configurar un origen de datos.
Configuración de la aplicación con el complemento Maven para Azure App Service
Vamos a configurar la aplicación mediante la ejecución del objetivo de configuración en el complemento de Maven para Azure App Service.
./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.9.0:config
Importante
Si ha cambiado la región del servidor MySQL, debe cambiar también el servidor de aplicaciones de Java EE a la misma región para minimizar los retrasos de latencia.
En el comando, seleccione Java 11 para la versión de Java y JBoss EAP 7 para la pila del entorno de ejecución.
Elemento de entrada | Value |
---|---|
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 |
Después de ejecutar el comando, verá mensajes como el siguiente en el terminal:
$ ./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] ------------------------------------------------------------------------
$
Una vez que se haya completado el comando, podrá ver que se agrega la entrada siguiente en el archivo pom.xml
de 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>
Importante
Compruebe el elemento <region>
. Si no es la misma ubicación de instalación que MySQL, cámbiela a la misma ubicación.
Después de agregar la configuración anterior para la implementación en Azure, agregue las siguientes entradas XML para implementar el archivo de inicio. El recurso <type>startup</type>
implementa el script especificado como startup.sh
(Linux) o startup.cmd
(Windows) en /home/site/scripts/
. Configuraremos el script de inicio en el paso siguiente.
<!-- 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 -->
Nota:
Puede especificar el siguiente recurso que se va a implementar en el código XML:
type=<war|jar|ear|lib|startup|static|zip>
type=war
implementará el archivo war en/home/site/wwwroot/app.war
si no se especifica el elementopath
.type=war&path=webapps/<appname>\
se comportará exactamente igual que wardeploy descomprimiendo la aplicación en /home/site/wwwroot/webapps/<appname>type=jar
implementará el archivo war en/home/site/wwwroot/app.jar
. Se omitirá el parámetropath
.type=ear
implementará el archivo war en/home/site/wwwroot/app.ear
. Se omitirá el parámetropath
.type=lib
implementará el archivo jar en /home/site/libs. Se debe especificar el parámetropath
.type=static
implementará el script en/home/site/scripts
. Se debe especificar el parámetropath
.type=startup
implementará el script comostartup.sh
(Linux) ostartup.cmd
(Windows) en/home/site/scripts/
. Se omitirá el parámetropath
.type=zip
descomprimirá el archivo ZIP en/home/site/wwwroot
. El parámetropath
es opcional.
Ahora, compruebe los valores del nombre del grupo de recursos y el nombre de la aplicación en el archivo XML anterior. Anote estos nombres o, mejor, asígnelos a variables de entorno.
<resourceGroup>jakartaee-app-on-jboss-1625038814881-rg</resourceGroup>
<appName>jakartaee-app-on-jboss-1625038814881</appName>
Si usa Bash, configure las variables de entorno con el comando siguiente. Usará estos valores más adelante.
export RESOURCEGROUP_NAME=jakartaee-app-on-jboss-1625038814881-rg
export WEBAPP_NAME=jakartaee-app-on-jboss-1625038814881
Compilación de la aplicación de Java EE
Después de configurar las opciones de implementación de Azure App Service, compile y empaquete el código fuente.
./mvnw clean package
Aparece la salida siguiente en el terminal:
[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] ------------------------------------------------------------------------
Implementación de la aplicación de Java EE en JBoss EAP en Azure App Service
Después de compilar y empaquetar el código, implemente la aplicación:
./mvnw azure-webapp:deploy
Aparece el mensaje siguiente en el terminal:
[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] ------------------------------------------------------------------------
Anote la dirección URL de la aplicación implementada, específicamente la siguiente línea de la salida de Maven:
[INFO] Successfully deployed the artifact to https://jakartaee-app-on-jboss-1625038814881.azurewebsites.net
Configuración de una conexión de base de datos
La aplicación de ejemplo se conecta a la base de datos MySQL y muestra los datos.
En la configuración del proyecto de Maven en pom.xml
, se ha especificado el controlador JDBC de MySQL de la siguiente manera:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-jdbc-driver}</version>
</dependency>
Como resultado, JBoss EAP instala automáticamente el controlador JDBC en el paquete de implementación (ROOT.war
). Puede hacer referencia al nombre del controlador JDBC de MySQL de la siguiente manera:
ROOT.war_com.mysql.cj.jdbc.Driver_8_0
Creación del objeto DataSource de MySQL en JBoss EAP
Para acceder a Azure Database for MySQL, debe configurar el objeto DataSource
en JBoss EAP y especificar el nombre de JNDI en el código fuente.
Para crear un objeto DataSource
de MySQL en JBoss EAP, se ha creado el archivo de script de shell siguiente. El archivo de script es createMySQLDataSource.sh
, en el directorio /WEB-INF
.
Nota:
En el script, se enlaza el objeto DataSource de MySQL mediante un comando de la CLI de JBoss. La cadena de conexión, el nombre de usuario y la contraseña usan las variables de entorno MYSQL_CONNECTION_URL
, MYSQL_USER
y MYSQL_PASSWORD
.
El origen del archivo de script se muestra a continuación. Este archivo de script ya se ha cargado en App Service, pero aún no se ha configurado para invocarse.
#!/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
Ahora, configure la instancia de App Service para que invoque al script de inicio:
az webapp config set --startup-file '/home/site/scripts/startup.sh' \
-n ${WEBAPP_NAME} \
-g ${RESOURCEGROUP_NAME}
Después de la ejecución del script, se le invocará cada vez que se reinicie el servidor de aplicaciones.
Nota:
Si el artefacto de implementación no es ROOT.war
, también tendrá que cambiar el valor de --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_8_0
.
Configuración de las variables de entorno para conectarse a MySQL
Después de configurar el script de inicio, configure App Service para que use determinadas variables de entorno:
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
Sugerencia
Los valores de MYSQL_CONNECTION_URL
, MYSQL_USER
y MYSQL_PASSWORD
se han establecido en la unidad anterior.
Confirmación de la referencia de DataSource en el código
Para acceder a la base de datos MySQL desde la aplicación, debe configurar la referencia del origen de datos en el proyecto de aplicación. Se ha implementado el código de acceso a la base de datos mediante la API Persistence de Java (JPA).
La configuración de la referencia de DataSource
se ha agregado en persistence.xml
, que es el archivo de configuración de JPA.
Acceda al archivo siguiente:
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── META-INF
│ │ │ └── persistence.xml
Compruebe si el nombre de DataSource
coincide con el nombre usado en la configuración. El código ya ha creado el nombre de JNDI como 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>
Después, puede acceder a la base de datos MySQL a la que se hace referencia en el nombre de unidad PersistenceContext
como se indica a continuación:
@Transactional(REQUIRED)
@RequestScoped
public class CityService {
@PersistenceContext(unitName = "JPAWorldDatasourcePU")
EntityManager em;
Acceso a la aplicación
En la aplicación de ejemplo, se han implementado tres puntos de conexión REST. Puede acceder a la aplicación y validar estos puntos de conexión mediante un explorador web o un comando curl
.
Para acceder a la aplicación, debe hacer referencia a su dirección URL, que ha obtenido de una sección anterior:
[INFO] Successfully deployed the artifact to
https://jakartaee-app-on-jboss-1606464084546.azurewebsites.net
Ejecute el comando siguiente para obtener toda la información de continentes en formato JSON.
$ curl https://${WEBAPP_NAME}.azurewebsites.net/area
["North America","Asia","Africa","Europe","South America","Oceania","Antarctica"]$
Si especifica el continente en la dirección URL, puede obtener todos los países o regiones del continente especificado.
$ 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"
}
....
Por último, si especifica un código de país o región después de /countries
, puede obtener todas las ciudades, con una población superior a 1 millón dentro del país o región.
$ 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"
Resumen del ejercicio
Ahora ha validado los puntos de conexión REST de la aplicación y ha probado que puede obtener datos de la base de datos MySQL.
En la unidad siguiente, examinará los registros del servidor.