Quarkus:使用来自JBoss EAP Quickstart的helloworld示例升级应用程序

大家好,本博客,以及Quarkus系列的第四篇! (顺便说一下,注册并进入我们的网络研讨会“ 这是Quarkus-Kubernetes本机Java框架 ”,该研讨会将于5月27日举行。我们将展示如何从头开始或转移现成的解决方案。)



一篇文章是关于Quarkus如何将MicroProfile和Spring结合起来的。回想一下Quarkus被定位为“超快速亚原子Java”,它是“面向Kubernetes的Java堆栈,由GraalVM和OpenJDK HotSpot进行了优化,并从最佳的库和标准中进行了编译。”今天,我们展示如何使用Red Hat JBoss企业应用程序平台(JBoss EAP)快速入门资料库中的helloworld 应用程序使用Quarkus功能升级现有的Java应用程序。使用Quarkus支持的CDI和Servlet 3技术。

在这里需要特别注意的是,Quarkus和JBoss EAP都专注于使用按照最高标准构建的工具。JBoss EAP上没有运行任何应用程序吗?没问题,它可以使用Red Hat Application Migration Toolkit轻松地从当前应用程序服务器迁移到JBoss EAP 之后,可以在helloworld模块github.com/mrizzi/jboss-eap-quickstarts/tree/quarkus存储库中获得升级代码的最终版本和工作版本 这篇文章是使用Quarkus教程编写的,主要是创建第一个应用程序和构建本机可执行文件



我们得到一个代码


首先,创建JBoss EAP quickstarts存储库的本地克隆

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

看看原始的helloworld如何运作


实际上,此应用程序的本质从名称上就很明显,但是我们将严格科学地升级其代码。因此,首先,以原始形式查看此应用程序。

展开helloworld

1.打开终端,然后转到JBoss EAP文件夹的根目录(可以在此处下载),即进入EAP_HOME文件夹。

2.使用默认配置文件启动JBoss EAP服务器:

$ EAP_HOME/bin/standalone.sh

注意:在Windows上,EAP_HOME \ bin \ standalone.bat脚本用于运行。

几秒钟后,以下内容应出现在日志中:

[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.打开浏览器127.0.0.1:8080并查看以下内容:



图。1. JBoss EAP主页。

4.按照“ 构建和部署快速入门”手册中的说明进行操作:部署helloworld并执行(从项目根文件夹)以下命令:

$ mvn clean install wildfly:deploy

成功在日志中执行此命令后,我们将看到类似以下内容:

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

因此,在JBoss EAP上首次部署helloworld应用程序仅花了8秒钟以上。

我们

严格按照《访问应用程序指南》测试helloworld代理,在浏览器中打开127.0.0.1:8080 / helloworld并看到以下内容:



图。2.来自JBoss EAP的原始Hello World。

进行

更改将输入参数createHelloMessage(字符串名称)从World更改为Marco:

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

再次,运行以下命令:

$ mvn clean install wildfly:deploy

然后,我们在浏览器中刷新页面,然后看到文本已更改:



图。3.您好,JBoss EAP的Marco。

我们回滚helloworld部署并退出JBoss EAP,

这是可选的,但是如果要取消部署,可以使用以下命令来完成:

$ mvn clean install wildfly:undeploy

要关闭JBoss EAP实例,只需在终端窗口中按Ctrl +C。

升级helloworld


现在,让我们升级原始的helloworld应用程序。

创建一个新分支

快速入门项目完成后,创建一个新的工作分支:

$ git checkout -b quarkus 7.2.0.GA

更改pom.xml文件

我们将从pom.xml文件开始更改应用程序。为了使Quarkus可以在其中插入XML块,请在helloworld文件夹中执行以下命令:

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

在撰写本文时,使用的版本为0.23.2。Quarkus通常有新版本;您可以在github.com/quarkusio/quarkus/releases/latest上找到最新版本

上面的命令会将以下元素插入pom.xml:

  • <quarkus.version>属性,指定要使用的Quarkus版本。
  • <dependencyManagement>块,用于导入Quarkus BOM(物料清单),以便不为每个Quarkus依赖项添加版本。
  • quarkus-maven-plugin插件,负责打包应用程序并提供开发模式。
  • 用于创建应用程序可执行文件的本机配置文件。

另外,我们手动对pom.xml进行以下更改:

  1. <groupId> <parent> <artifactId>. <parent>, <groupId>.
  2. <parent>, Quarkus pom JBoss.
  3. <version> <artifactId>. .
  4. <packaging>, WAR, JAR.
  5. :
    1. javax.enterprise:cdi-api io.quarkus:quarkus-arc, <scope>provided</scope>, ( ) Quarkus- injection CDI.
    2. 我们将org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec的依赖关系更改为io.quarkus:quarkus-undertow,删除了<scope>提供的</ scope>,因为(根据码头)此Quarkus扩展提供了servlet支持。的。
    3. 我们删除了org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec依赖项,因为它们与我们刚刚更改的依赖项捆绑在一起。


进行了所有更改的pom.xml文件的版本位于github.com/mrizzi/jboss-eap-quickstarts/blob/quarkus/helloworld/pom.xml

请注意,上面的mvn io.quarkus:quarkus-maven-plugin:0.23.2:create命令不仅更改pom.xml文件,而且还向项目添加了许多组件,即以下文件和文件夹:

  • mvnw and mvnw.cmd .mvn: Maven Wrapper Maven Maven .
  • docker ( src/main/): Dockerfile native jvm ( .dockerignore).
  • resources ( src/main/): application.properties Quarkus index.html ( . Run the modernized helloworld ).

我们启动helloworld
为了测试该应用程序,我们使用quarkus:dev,它在开发模式下启动Quarkus(有关更多详细信息,请参见Development Mode手册中的本节)。

注意:此步骤可能会导致错误,因为我们尚未进行所有必要的更改。

现在运行命令以检查其工作方式:

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

所以,它不起作用...为什么呢?

UnsatisfiedResolutionException异常指向HelloService类,该类是HelloWorldServlet类的成员(java成员:org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService)。问题在于HelloWorldServlet需要注入的HelloService实例,但无法找到(尽管这两个类都在同一包中)。

现在该回到文档并阅读Quarkus的工作原理了注入因此,上下文和依赖注入(CDI)。因此,我们打开“上下文和依赖项注入”指南,并在“ Bean发现”部分中进行了阅读:“不搜索没有注释定义bean的bean类。”

我们看一下HelloService类-它确实没有这样的注释。因此,必须添加它,以便Quarkus可以搜索和查找bean。由于这是一个无状态对象,因此我们可以按如下所示添加@ApplicationScoped批注:

@ApplicationScoped
public class HelloService {

注意:在这里,开发环境可能会要求您添加所需的软件包(请参见下面的行),这必须手动完成,如下所示:

import javax.enterprise.context.ApplicationScoped;

如果不确定完全设置源bean时使用哪个范围,请查看JSR 365文档:Java 2.0的上下文和依赖注入-默认范围

再一次,我们尝试使用命令./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]

现在一切都没有错误。

我们推出升级后的HelloWorld
因为它是写在日志中,打开浏览器0.0.0.0:8080(默认Quarkus起始页),看看这个:



图。4. Quarkus开发者的起始页面。

此应用程序的WebServlet批注具有以下上下文定义:

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

因此,我们去0.0.0.0:8080 / HelloWorld的在浏览器中看到如下:



图。5:Hello World应用程序的Quarkus开发页面。

好吧,一切正常。

现在,我们正在更改代码。请注意,./mvnw编译quarkus:dev命令仍在起作用,我们不会停止它。现在,让我们尝试对代码本身进行相同的微不足道的更改,并查看Quarkus如何使开发人员的工作更轻松:

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

保存文件,然后刷新网页以查看Hello Marco,如以下屏幕截图所示:



图。6. Quarkus开发人员中的Hello Marco页面。

现在检查终端中的输出:

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

页面刷新触发了对源代码更改的检测,并且Quarkus自动执行“停止启动”过程。所有这些操作仅需0.371秒即可完成(这就是非常“超快速的亚原子Java”)。

我们将helloworld内置到JAR包中,
现在代码可以正常工作了,我们使用以下命令将其打包:

$ ./mvnw clean package

此命令在/ target文件夹中创建两个JAR文件:helloworld-.jar文件,它是Maven团队与项目类和资源一起组装的标准工件。 helloworld文件是Runner.jar,它是一个可执行的JAR。

请注意,这不是uber-jar,因为所有依赖项都被简单地复制到/ target / lib文件夹(而不是打包到JAR文件中)。因此,要从另一个文件夹或其他主机上运行此JAR,您需要同时复制JAR文件和/ lib文件夹,因为JAR包中MANIFEST.MF文件中的Class-Path元素包含来自以下位置的JAR的显式列表lib文件夹。
要了解如何创建uber-jar应用程序,请参阅Uber-Jar Creation教程

启动打包在JAR中的helloworld

现在,您可以使用标准java命令运行我们的JAR:

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

完成所有这些操作后,转到浏览器,位于0.0.0.0:8080上,并检查是否一切正常。

将helloworld放入本机可执行文件

因此,我们的helloworld可以作为使用Quarkus依赖项的独立Java应用程序。但是您可以走得更远,然后将其转换为本地可执行文件。

安装GraalVM
首先,为此,您需要安装必要的工具:

1 . github.com/oracle/graal/releases/tag/vm-19.2.0.1下载GraalVM 19.2.0.1

2.展开下载的档案:

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

3.转到untar文件夹。

4.运行以下命令以下载并添加本机映像:

$ ./bin/gu install native-image

5.我们将在步骤2中创建的文件夹注册到环境变量GRAALVM_HOME中:

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

有关其他操作系统的更多信息和安装说明,请参阅构建本机可执行文件-前提条件

我们将helloworld构建为本地可执行文件。
我们阅读了《构建本地可执行文件—制作本地可执行文件手册》:“现在为我们的应用程序创建本地可执行文件,以减少启动时间和磁盘大小。可执行文件将具有运行应用程序所需的一切,包括JVM计算机(或更确切地说,其截短的版本,仅包含运行应用程序所需的内容)以及我们的应用程序本身。”

要创建本机可执行文件,必须启用Maven本机配置文件:

$ ./mvnw package -Pnative

我们的组装花了1分10秒,最终的helloworld文件-运行程序f在/ target文件夹中创建。

我们启动本机可执行文件helloworld

在上一步中,我们获得了可执行文件/ target / helloworld-运行程序。现在运行它:

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

再次,打开浏览器0.0.0.0:8080并检查是否一切正常。

未完待续!

我们认为,本文中使用的Quarkus功能(尽管是最简单的示例)使Java应用程序现代化的方法应在现实生活中积极应用。在这种情况下,您可能会遇到许多问题,我们将在下一篇文章中部分地解决这些问题,该解决方案将集中于如何测量内存消耗以评估性能改进,这是应用程序现代化整个过程的重要组成部分。

All Articles