Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Olá a todos neste blog, aqui está o quarto post da série Quarkus!

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Post anterior foi sobre como o Quarkus combina MicroProfile e Spring. Deixe-nos lembrá-lo que quarks está posicionado como “Java subatômico ultrarrápido”, também conhecido como “pilha Java orientada para Kubernetes, adaptada para GraalVM e OpenJDK HotSpot e montada a partir das melhores bibliotecas e padrões”. Hoje mostraremos como modernizar aplicativos Java existentes usando os recursos do Quarkus, usando o exemplo aplicativos helloworld do repositório de início rápido do Red Hat JBoss Enterprise Application Platform (JBoss EAP), que utiliza tecnologias CDI e Servlet 3 suportadas pelo Quarkus.

É importante observar aqui que tanto o Quarkus quanto o JBoss EAP enfatizam o uso de ferramentas tão baseadas em padrões quanto possível. Não possui um aplicativo em execução no JBoss EAP? Não tem problema, ele pode ser facilmente migrado do seu servidor de aplicativos atual para o JBoss EAP usando Kit de ferramentas de migração de aplicativos Red Hat. Após o qual a versão final e funcional do código modernizado estará disponível no repositório github.com/mrizzi/jboss-eap-quickstarts/tree/quarkus, no módulo Olá Mundo.

Ao escrever este post usamos Tutoriais do Quarkusprincipalmente Criando seu primeiro aplicativo e Construindo um Executável nativo.

Vamos pegar o código

Primeiro de tudo, vamos criar um clone local do repositório Guias de início rápido do JBoss EAP:

$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Cloning into 'jboss-eap-quickstarts'...
remote: Enumerating objects: 148133, done.
remote: Total 148133 (delta 0), reused 0 (delta 0), pack-reused 148133
Receiving objects: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, done.
Resolving deltas: 100% (66476/66476), done.
$ cd jboss-eap-quickstarts/helloworld/

Vamos ver como funciona o helloworld original

Na verdade, a essência desta aplicação fica clara pelo nome, mas iremos modernizar seu código de forma estritamente científica. Portanto, primeiro vamos dar uma olhada neste aplicativo em sua forma original.

Implantando helloworld

1. Abra um terminal e vá para a raiz da pasta JBoss EAP (você pode baixá-lo aqui), ou seja, para a pasta EAP_HOME.

2. Inicie o servidor JBoss EAP com o perfil padrão:

$ EAP_HOME/bin/standalone.sh

Nota: em Windows для запуска используется сценарий EAP_HOMEbinstandalone.bat.

Após alguns segundos, algo assim deverá aparecer no log:

[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) started in 3315ms - Started 306 of 527 services (321 services are lazy, passive or on-demand)

3. Abra em um navegador 127.0.0.1:8080 e vemos isto:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 1. Página inicial do JBoss EAP.

4. Siga as instruções do manual Crie e implante o início rápido: expanda helloworld e execute (da pasta raiz do projeto) o seguinte comando:

$ mvn clean install wildfly:deploy

Depois de executar este comando com sucesso, veremos algo como o seguinte no log:

[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 8.224 s

Portanto, a primeira implantação do aplicativo helloworld no JBoss EAP levou pouco mais de 8 segundos.

Testando olá mundo

Agindo estritamente de acordo com as instruções Acesse o Aplicativo, abra no navegador 127.0.0.1:8080/helloworld e vemos isto:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 2. Hello World original do JBoss EAP.

Fazendo mudanças

Altere o parâmetro de entrada createHelloMessage(String name) de World para Marco:

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Execute o seguinte comando novamente:

$ mvn clean install wildfly:deploy

Em seguida, atualizamos a página no navegador e vemos que o texto mudou:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 3. Olá Marco no JBoss EAP.

Reverter a implantação do helloworld e encerrar o JBoss EAP

Isso é opcional, mas se quiser cancelar a implantação, você pode fazer isso com o seguinte comando:

$ mvn clean install wildfly:undeploy

Para encerrar sua instância do JBoss EAP, simplesmente pressione Ctrl+C na janela do terminal.

Atualizando olá mundo

Agora vamos modernizar o aplicativo helloworld original.

Crie uma nova filial

Criamos um novo branch de trabalho após a conclusão do projeto de início rápido:

$ git checkout -b quarkus 7.2.0.GA

Alterando o arquivo pom.xml

Começaremos a alterar o aplicativo a partir do arquivo pom.xml. Para permitir que o Quarkus insira blocos XML nele, execute o seguinte comando na pasta helloworld:

$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create

Ao escrever este artigo, foi utilizada a versão 0.23.2. Quarkus frequentemente lança novas versões, você pode descobrir qual versão é a mais recente no site github.com/quarkusio/quarkus/releases/latest.

O comando acima irá inserir os seguintes elementos em pom.xml:

  • Propriedade , que especifica a versão do Quarkus a ser usada.
  • Bloquear importar a BOM (lista de materiais) do Quarkus, para não adicionar uma versão para cada dependência do Quarkus.
  • O plugin quarkus-maven é responsável por empacotar a aplicação e fornecer o modo de desenvolvimento.
  • O perfil nativo para criar executáveis ​​de aplicativos.

Além disso, fazemos manualmente as seguintes alterações em pom.xml:

  1. Retirando a etiqueta do bloco e coloque-o acima da tag . Porque na próxima etapa iremos remover o bloco , então você precisa salvar .
  2. Removendo um bloco , porque ao executar com o Quarkus, esse aplicativo não precisará mais de um pom pai do JBoss.
  3. Adicionar uma etiqueta e coloque-o sob a tag . Você pode especificar o número da versão desejada.
  4. Removendo a etiqueta , já que este aplicativo não é mais um WAR, mas um JAR normal.
  5. Modificamos as seguintes dependências:
    1. Altere a dependência javax.enterprise:cdi-api para io.quarkus:quarkus-arc, removendo oferecido , já que (de acordo com a documentação) esta extensão do Quarkus fornece injeção de dependências CDI.
    2. Altere a dependência org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec para io.quarkus:quarkus-undertow, removendo oferecido , porque (de acordo com a documentação) esta extensão do Quarkus fornece suporte para servlets.
    3. Removemos a dependência org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec, pois ela vem com as dependências que acabamos de alterar.

A versão do arquivo pom.xml com todas as alterações está localizada em github.com/mrizzi/jboss-eap-quickstarts/blob/quarkus/helloworld/pom.xml.

Observe que o comando mvn io.quarkus:quarkus-maven-plugin:0.23.2:create acima não apenas altera o arquivo pom.xml, mas também adiciona vários componentes ao projeto, ou seja, os seguintes arquivos e pastas:

  • Os arquivos mvnw e mvnw.cmd e a pasta .mvn: Maven Wrapper permitem executar projetos Maven de uma determinada versão do Maven sem instalar essa versão.
  • Pasta Docker (no diretório src/main/): contém exemplos de Dockerfiles para os modos nativo e jvm (junto com o arquivo .dockerignore).
  • Pasta Resources (no diretório src/main/): Contém um arquivo application.properties vazio e uma amostra da página inicial do Quarkus index.html (consulte Executar o helloworld modernizado para obter mais detalhes).

Inicie olá mundo
Para testar a aplicação, usamos quarkus:dev, que inicia o Quarkus em modo de desenvolvimento (para mais detalhes, veja esta seção do manual Modo de Desenvolvimento).

Nota: Esta etapa provavelmente resultará em um erro, pois ainda não fizemos todas as alterações necessárias.

Agora vamos executar o comando para ver como funciona:

$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Building Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Listening for transport dt_socket at address: 5005
INFO  [io.qua.dep.QuarkusAugmentor] Beginning quarkus augmentation
INFO  [org.jbo.threads] JBoss Threads version 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS bean [types=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], qualifiers=[@Default, @Any], target=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
	at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:841)
	at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:214)
	at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:106)
	at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:249)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at io.quarkus.deployment.ExtensionLoader$1.execute(ExtensionLoader.java:780)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:415)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
	at java.lang.Thread.run(Thread.java:748)
	at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS bean [types=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], qualifiers=[@Default, @Any], target=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
	at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:428)
	at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:371)
	at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:206)
	... 14 more

Então, não funciona... Por quê?

O UnsatisfiedResolutionException aponta para a classe HelloService, que é membro da classe HelloWorldServlet (membro java: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). O problema é que HelloWorldServlet precisa de uma instância injetada de HelloService e ela não pode ser encontrada (mesmo que ambas as classes estejam no mesmo pacote).

É hora de voltar para documentação e leia como funciona no Quarkus Injetar, e portanto Contextos e injeção de dependência (CDI). Portanto, abra o guia Contextos e Injeção de Dependências e na seção Descoberta de feijão lemos: “Uma classe de bean que não possui uma anotação de definição de bean não é pesquisada”.

Vejamos a classe HelloService - ela realmente não possui essa anotação. Portanto, ele deve ser adicionado para que o Quarkus possa pesquisar e encontrar o bean. E como este é um objeto sem estado, podemos facilmente adicionar a anotação @ApplicationScoped assim:

@ApplicationScoped
public class HelloService {

Nota: aqui o ambiente de desenvolvimento pode solicitar que você adicione o pacote necessário (veja a linha abaixo), e você terá que fazer isso manualmente, assim:

import javax.enterprise.context.ApplicationScoped;

Se você estiver em dúvida sobre qual escopo deve ser usado caso ele não esteja especificado para o bean fonte, leia a documentação JSR 365: Contextos e injeção de dependência para Java 2.0 — Escopo padrão.

Agora tentamos novamente iniciar o aplicativo com o comando ./mvnw compile quarkus:dev:

$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Building Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Listening for transport dt_socket at address: 5005
INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 576ms
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 1.083s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Agora tudo corre sem erros.

Lançando o helloworld modernizado
Conforme escrito no log, abra-o no navegador 0.0.0.0:8080 (a página inicial padrão do Quarkus) e vemos isto:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 4. Página inicial do desenvolvedor do Quarkus.

A anotação WebServlet para este aplicativo contém a seguinte definição de contexto:

@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {

Portanto, vamos no navegador para 0.0.0.0:8080/HelloWorld e vemos o seguinte:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 5: A página de desenvolvimento do Quarkus para o aplicativo Hello World.

Bem, tudo funciona.

Agora vamos fazer alterações no código. Observe que o comando ./mvnw compile quarkus:dev ainda está em execução e não temos intenção de interrompê-lo. Agora vamos tentar aplicar as mesmas alterações - muito triviais - no próprio código e ver como o Quarkus facilita a vida do desenvolvedor:

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Salve o arquivo e atualize a página da web para ver Hello Marco, conforme mostrado na imagem abaixo:

Quarkus: Modernização de aplicativos usando Helloworld como exemplo do JBoss EAP Quickstart

Arroz. 6. Olá página Marco no Quarkus dev.

Agora vamos verificar a saída no terminal:

INFO  [io.qua.dev] (vert.x-worker-thread-3) Changed source files detected, recompiling [/home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/src/main/java/org/jboss/as/quickstarts/helloworld/HelloWorldServlet.java]
INFO  [io.quarkus] (vert.x-worker-thread-3) Quarkus stopped in 0.003s
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Beginning quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Quarkus augmentation completed in 232ms
INFO  [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 started in 0.257s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (vert.x-worker-thread-3) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (vert.x-worker-thread-3) Installed features: [cdi]
INFO  [io.qua.dev] (vert.x-worker-thread-3) Hot replace total time: 0.371s

A atualização da página acionou a detecção de alterações no código-fonte e o Quarkus executou automaticamente um procedimento stop-start. E tudo isso foi concluído em apenas 0.371 segundos (aqui está, aquele “Java subatômico ultrarrápido”).

Construindo helloworld em um pacote JAR
Agora que o código funciona como deveria, vamos empacotá-lo com o seguinte comando:

$ ./mvnw clean package

Este comando cria dois arquivos JAR na pasta /target: o arquivo helloworld-.jar, que é um artefato padrão montado pela equipe Maven junto com as classes e recursos do projeto. E o arquivo helloworld-runner.jar, que é um JAR executável.

Observe que este não é um uber-jar, pois todas as dependências são simplesmente copiadas para a pasta /target/lib (não empacotadas em um arquivo JAR). Portanto, para executar este JAR de outra pasta ou em outro host, você precisa copiar o próprio arquivo JAR e a pasta /lib lá, visto que o elemento Class-Path no arquivo MANIFEST.MF no pacote JAR contém uma listagem explícita de JARs das pastas lib
Para aprender como criar aplicativos uber-jar, consulte o tutorial Criação do Uber-Jar.

Inicie o helloworld empacotado em JAR

Agora podemos executar nosso JAR usando o comando java padrão:

$ java -jar ./target/helloworld-<version>-runner.jar
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 0.673s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile prod activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Depois de tudo isso feito, acesse seu navegador em 0.0.0.0:8080 e verifique se tudo funciona como deveria.

Compilando helloworld em um arquivo executável nativo

Portanto, nosso helloworld é executado como um aplicativo Java independente usando dependências do Quarkus. Mas você pode ir além e transformá-lo em um arquivo executável nativo.

Instalando GraalVM
Em primeiro lugar, para isso é necessário instalar as ferramentas necessárias:

1. Baixe GraalVM 19.2.0.1 em github.com/oracle/graal/releases/tag/vm-19.2.0.1.

2. Expanda o arquivo baixado:

$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz

3. Vá para a pasta descompactar.

4. Execute o comando abaixo para baixar e adicionar a imagem nativa:

$ ./bin/gu install native-image

5. Registre a pasta criada no passo 2 na variável de ambiente GRAALVM_HOME:

$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)

Para mais informações e instruções de instalação em outros sistemas operacionais, consulte o manual Construindo um Executável Nativo – Pré-requisitos.

Construindo helloworld em um arquivo executável nativo
Lendo o manual Construindo um executável nativo – Produzindo um executável nativo: “Agora vamos criar um arquivo executável nativo para nosso aplicativo para reduzir o tempo de inicialização e o tamanho do disco. O arquivo executável terá tudo o que é necessário para executar a aplicação, incluindo a JVM (ou melhor, uma versão truncada dela, contendo apenas o que é necessário para executar a aplicação) e a nossa própria aplicação.”

Para criar um arquivo executável nativo, você precisa habilitar o perfil Maven nativo:

$ ./mvnw package -Pnative

Nossa construção levou um minuto e 10 segundos, e o arquivo helloworld—runner f final foi criado na pasta /target.

Execute o executável nativo helloworld

Na etapa anterior, recebemos o arquivo executável /target/helloworld—runner. Agora vamos executá-lo:

$ ./target/helloworld-<version>-runner
INFO  [io.quarkus] (main) Quarkus 0.23.2 started in 0.006s. Listening on: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profile prod activated.
INFO  [io.quarkus] (main) Installed features: [cdi]

Abra-o no navegador novamente 0.0.0.0:8080 e verifique se tudo funciona como deveria.

Para continuar!

Acreditamos que o método de modernização de aplicativos Java usando os recursos do Quarkus discutido neste post (embora usando um exemplo simples) deva ser usado ativamente na vida real. Ao fazer isso, você provavelmente encontrará uma série de problemas, que abordaremos parcialmente no próximo post, onde falaremos sobre como medir o consumo de memória para avaliar melhorias de desempenho, parte importante de todo o processo de modernização de aplicações.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção DDoS, servidores VPS VDS 🔥 Compre hospedagem de sites confiável com proteção contra DDoS, servidores VPS/VDS | ProHoster