Exercício - Implantar um aplicativo Jakarta EE no JBoss EAP no Serviço de Aplicativo do Azure

Concluído

Nesta unidade, você implanta um aplicativo Jakarta EE no Red Hat JBoss Enterprise Application Platform (JBoss EAP) no Serviço de Aplicativo do Azure. Use o plug-in Maven para o Serviço de Aplicativo do Azure para configurar o projeto, compilar e implantar o aplicativo e configurar uma fonte de dados.

Configurar o aplicativo

Configure o aplicativo com o plug-in Maven para o Serviço de Aplicativo do Azure usando as seguintes etapas:

  1. Execute a meta de configuração do plug-in do Azure interativamente usando o seguinte comando:

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

    Importante

    Se você alterar a região do seu servidor MySQL, você deve corresponder essa região à região do seu servidor de aplicativos Jakarta EE para minimizar os atrasos de latência.

  2. Use os valores na tabela a seguir para responder aos prompts interativos:

    Elemento de entrada Valor
    Create new run configuration (Y/N) [Y]: Y
    Define value for OS [Linux]: Linux
    Define value for javaVersion [Java 17]: 1: Java 17
    Define value for runtimeStack: 3: Jbosseap 7
    Define value for pricingTier [P1v3]: P1v3
    Confirm (Y/N) [Y]: Y

    A seguinte saída é típica:

    [INFO] Saving configuration to pom.
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  03:00 min
    [INFO] Finished at: 2025-02-21T06:24:11+09:00
    [INFO] ------------------------------------------------------------------------
    

    Depois de usar o comando Maven, o exemplo a seguir é uma adição típica ao seu arquivo Maven pom.xml:

    <build>
      <finalName>ROOT</finalName>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.4.0</version>
        </plugin>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-webapp-maven-plugin</artifactId>
            <version>2.13.0</version>
            <configuration>
                <schemaVersion>v2</schemaVersion>
                <resourceGroup>jakartaee-app-on-jboss-rg</resourceGroup>
                <appName>jakartaee-app-on-jboss</appName>
                <pricingTier>P1v3</pricingTier>
                <region>centralus</region>
                <runtime>
                    <os>Linux</os>
                    <javaVersion>Java 17</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>
    
  3. Verifique o elemento <region> no seu ficheiro pom.xml. Se o seu valor não corresponder ao local de instalação do MySQL, altere-o para o mesmo local.

  4. Use o exemplo a seguir para modificar o webContainer valor em seu arquivo pom.xml para Jbosseap 8, para o ambiente JBoss EAP 8 no Serviço de Aplicativo do Azure:

    Dica

    A partir de fevereiro de 2025, a última versão disponível do JBoss EAP é a 8.0 Update 4.1.

    <runtime>
        <os>Linux</os>
        <javaVersion>Java 17</javaVersion>
        <webContainer>Jbosseap 8</webContainer> <!-- Change this value -->
    </runtime>
    
  5. Adicione o seguinte XML ao <resources> elemento do seu arquivo pom.xml . Essa configuração é usada para implantar o arquivo de inicialização, que você atualiza posteriormente nesta unidade.

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

    O valor de recurso <type> implanta o script especificado como o arquivo startupstartup.sh para Linux ou startup.cmd para Windows. O local de implantação é /home/site/scripts/.

    Observação

    Você pode escolher a opção de implantação e o local de implantação especificando type de uma das seguintes maneiras:

    • type=war implanta o arquivo WAR em /home/site/wwwroot/app.war se path não for especificado.
    • type=war&path=webapps/<appname> implanta o arquivo WAR em /home/site/wwwroot/webapps/<appname>.
    • type=jar implanta o arquivo WAR em /home/site/wwwroot/app.jar. O parâmetro path é ignorado.
    • type=ear implanta o arquivo WAR em /home/site/wwwroot/app.ear. O parâmetro path é ignorado.
    • type=lib implanta o JAR em /home/site/libs. Você deve especificar path parâmetro.
    • type=static implanta o script em /home/site/scripts. Você deve especificar o path parâmetro.
    • type=startup implanta o script como startup.sh no Linux ou startup.cmd no Windows. O script é implantado em /home/site/scripts/. O parâmetro path é ignorado.
    • type=zip Descompacta o arquivo .zip para /home/site/wwwroot. O path parâmetro é opcional.
  6. Verifique os valores para os elementos resourceGroup e appName no seu arquivo pom.xml.

  7. Atribua os valores para resourceGroup e appName para variáveis de ambiente usando os seguintes comandos:

    export RESOURCE_GROUP_NAME=<resource-group>
    export WEB_APP_NAME=<app-name>
    

Compilar e construir o aplicativo Jakarta EE

Depois de definir as configurações de implantação do Serviço de Aplicativo do Azure, compile e empacote o código-fonte usando o seguinte comando:

./mvnw clean package

A seguinte saída é típica:

[INFO] --- war:3.4.0:war (default-war) @ jakartaee-app-on-jboss ---
[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] Building war: /private/tmp/mslearn-jakarta-ee-azure/target/ROOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.881 s
[INFO] Finished at: 2025-02-21T06:32:30+09:00
[INFO] ------------------------------------------------------------------------

Implantar o aplicativo Jakarta EE no JBoss EAP no Serviço de Aplicativo do Azure

Depois de compilar e empacotar o código, implante o aplicativo usando o seguinte comando:

./mvnw azure-webapp:deploy

Você deve ver a saída que inclui uma mensagem de êxito e a URL do aplicativo implantado. Certifique-se de salvar o URL para uso posterior.

Configurar uma conexão de banco de dados

O aplicativo de exemplo se conecta ao seu banco de dados MySQL e exibe dados. A configuração do projeto Maven no arquivo pom.xml especifica o driver JDBC MySQL, conforme mostrado no exemplo a seguir:

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

Como resultado, o JBoss EAP instala automaticamente o driver ROOT.war_com.mysql.cj.jdbc.Driver_9_2 JDBC no seu pacote de implementação ROOT.war.

Criar o objeto MySQL DataSource no JBoss EAP

Para acessar o Banco de Dados do Azure para MySQL, você precisa configurar o DataSource objeto no JBoss EAP e especificar o nome JNDI (Java Naming and Directory Interface) em seu código-fonte. Para criar um objeto MySQL DataSource no JBoss EAP, use o script de shell de inicialização /WEB-INF/createMySQLDataSource.sh . O exemplo a seguir mostra uma versão não configurada do script já no Serviço de Aplicativo do Azure:

#!/bin/bash
# In order to use the variables in 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=${AZURE_MYSQL_CONNECTIONSTRING}&characterEncoding=utf8&sslMode=REQUIRED&serverTimezone=UTC&authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin \
--driver-name=ROOT.war_com.mysql.cj.jdbc.Driver_9_2 \
--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

Observação

Quando você cria a fonte de dados, você não especifica uma senha para a conexão MySQL. A variável AZURE_MYSQL_CONNECTIONSTRING de ambiente é especificada no --connection-url parâmetro. Essa variável de ambiente é definida automaticamente quando a conexão de serviço é criada posteriormente.

O valor da conexão de serviço é definido como jdbc:mysql://$MYSQL_SERVER_INSTANCE.mysql.database.azure.com:3306/world?serverTimezone=UTC&sslmode=required&user=aad_jbossapp, que utiliza o nome de utilizador aad_jbossapp sem uma palavra-passe. Ao anexar &authenticationPlugins=com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin a essa URL, a autenticação do Microsoft Entra ID é habilitada para o aad_jbossapp usuário.

Configure sua instância do Serviço de Aplicativo para invocar o script de inicialização usando o seguinte comando:

az webapp config set \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name ${WEB_APP_NAME} \
    --startup-file '/home/site/scripts/startup.sh'

Depois que o script é executado, o servidor de aplicativos o invoca sempre que o servidor de aplicativos é reiniciado.

Observação

Se o artefato de implantação não for ROOT.war, altere também o valor --driver-name=YOUR_ARTIFACT.war_com.mysql.cj.jdbc.Driver_9_2.

Configurar a conexão de serviço para o servidor flexível MySQL

Depois de configurar o script de inicialização, configure o Serviço de Aplicativo para usar o Service Connector para a conexão de servidor flexível do MySQL usando as seguintes etapas:

  1. Defina variáveis de ambiente usando os seguintes comandos:

    export PASSWORDLESS_USER_NAME_SUFFIX=jbossapp
    export SOURCE_WEB_APP_ID=$(az webapp list \
        --resource-group  $RESOURCE_GROUP_NAME \
        --query "[0].id" \
        --output tsv)
    export MYSQL_ID=$(az mysql flexible-server list \
        --resource-group $RESOURCE_GROUP_NAME \
        --query "[0].id" \
        --output tsv)
    export TARGET_MYSQL_ID=$MYSQL_ID/databases/world
    export MANAGED_ID=$(az identity list \
        --resource-group $RESOURCE_GROUP_NAME \
        --query "[0].id" \
        --output tsv)
    

    As variáveis de ambiente são usadas para os seguintes fins:

    • PASSWORDLESS_USER_NAME_SUFFIX é o sufixo para o nome de usuário usado para se conectar ao servidor flexível MySQL. O nome de usuário criado tem o prefixo aad_ seguido pelo sufixo especificado.
    • SOURCE_WEB_APP_ID é a ID da instância do Serviço de Aplicativo do Azure usada para se conectar ao servidor flexível MySQL.
    • MYSQL_ID é o ID do servidor flexível MySQL.
    • TARGET_MYSQL_ID especifica o nome da base de dados como $MYSQL_ID/databases/world para estabelecer uma ligação com um utilizador que tem permissão para aceder à base de dados world.
    • MANAGED_ID é a identidade gerenciada usada para se conectar ao servidor flexível MySQL.
  2. Adicione a extensão para serviceconnector-passwordless e crie a conexão de serviço usando os seguintes comandos:

    az extension add \
        --name serviceconnector-passwordless \
        --upgrade
    az webapp connection create mysql-flexible \
        --resource-group ${RESOURCE_GROUP_NAME} \
        --connection $PASSWORDLESS_USER_NAME_SUFFIX \
        --source-id $SOURCE_WEB_APP_ID \
        --target-id $TARGET_MYSQL_ID \
        --client-type java \
        --system-identity mysql-identity-id=$MANAGED_ID
    

    Observação

    Se você receber uma mensagem de erro como Resource '********-****-****-****-************' does not exist or one of its queried reference-property objects are not present., execute novamente o comando após alguns segundos.

  3. No prompt SQL, verifique a lista de usuários registrados no MySQL usando a seguinte consulta:

    SELECT user, host, plugin FROM mysql.user;
    

    A seguinte saída é típica:

    +----------------------------------+-----------+-----------------------+
    | user                             | host      | plugin                |
    +----------------------------------+-----------+-----------------------+
    | aad_jbossapp                     | %         | aad_auth              |
    | azureuser                        | %         | mysql_native_password |
    | $CURRENT_AZ_LOGIN_USER_NAME#EXT#@| %         | aad_auth              |
    | azure_superuser                  | 127.0.0.1 | mysql_native_password |
    | azure_superuser                  | localhost | mysql_native_password |
    | mysql.infoschema                 | localhost | caching_sha2_password |
    | mysql.session                    | localhost | caching_sha2_password |
    | mysql.sys                        | localhost | caching_sha2_password |
    +----------------------------------+-----------+-----------------------+
    8 rows in set (2.06 sec)
    

    Você deve ver um aad_jbossapp usuário que usa o aad_auth plugin. A partir do JBoss EAP implantado no Azure, você pode se conectar ao servidor flexível MySQL usando o aad_jbossapp nome de usuário sem uma senha.

Confirme a referência DataSource no código

Para acessar o banco de dados MySQL de seu aplicativo, você precisa configurar a referência da fonte de dados em seu projeto de aplicativo.

O código de acesso ao banco de dados é implementado usando a Java Persistence API (JPA). A configuração para a DataSource referência está no arquivo de configuração JPA persistence.xml.

Use as seguintes etapas para confirmar a DataSource referência:

  1. Abra o ficheiro src/main/resources/META-INF/persistence.xml e verifique se o nome DataSource corresponde ao nome usado na configuração. O script de inicialização já criou o nome JNDI como java:jboss/datasources/JPAWorldDataSource, conforme mostrado no exemplo a seguir:

    <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>
    
  2. Acesse o banco de dados MySQL no nome da unidade, PersistenceContext conforme mostrado no exemplo a seguir:

    @Transactional(REQUIRED)
    @RequestScoped
    public class CityService {
    
        @PersistenceContext(unitName = "JPAWorldDatasourcePU")
        EntityManager em;
    

Aceda à aplicação

O aplicativo de exemplo implementa três pontos de extremidade REST. Para acessar o aplicativo e recuperar dados, use as seguintes etapas:

  1. Use seu navegador para navegar até a URL do aplicativo, que foi mostrada na saída quando você implantou o aplicativo.

  2. Para obter todas as informações do continente no formato JSON, use o método GET no endpoint area.

    Captura de ecrã do ponto de extremidade da área.

  3. Para obter todos os países e regiões em um continente especificado, use o método GET no endpoint area e especifique um path parameter continent.

    Captura de ecrã do endpoint de área com um parâmetro de caminho de continente.

  4. Para obter todas as cidades que têm uma população superior a um milhão no país ou região especificado, utilize o método GET no ponto de extremidade countries e especifique um parâmetro de caminho countrycode.

    Captura de tela do ponto de extremidade de países com o parâmetro countrycode path.

Resumo do exercício

Nesta unidade, você validou os endpoints REST do aplicativo e confirmou que seu aplicativo pode obter dados do seu banco de dados MySQL. Na próxima unidade, você examina os logs do servidor.