官方文档:CREATING YOUR FIRST APPLICATION
准备
使用Quarkus需要准备环境
- GraalVM Open-JDK-11
- Maven 3.8.1+
- Quarkus 2.6.2.Final
更多内容查看文档:https://quarkus.io/guides/getting-started
下载
Quarkus官方网址:https://quarkus.io
GraalVM下载地址:
- 最新版本:https://www.graalvm.org/downloads/
- 更多版本:https://github.com/graalvm/graalvm-ce-builds/releases
下载时候注意Graal有基于不同JDK版本的支持,如JDK8,JDK11,JDK11,可根据自己需求下载。
环境变量
配置环境变量方式同Java一样
- 配置JAVAHOME或者GRAALVM_HOME _C:\Program Files\Java\graalvm-ce-java8-21.0.0.2
- 环境变量配置不生效解决方案:
多个JDK版本情况下出现环境变量切换不生效,Windows本身系统system32里面的环境变量加载等级要优先于用户设置的环境变量,其根本原因是%JAVA_HOME%在path中配置的位置在%SystemRoot%\system32;后面,放到path最前面就好了。
配置好后执行命令确保使用的是GraalVM
C:\Users\starsray>java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-b07)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.0.2 (build 25.282-b07-jvmci-21.0-b06, mixed mode)
启动
创建应用
使用maven创建
使用maven来快速创建一个应用,创建的位置在当前命令执行终端所在的根目录,项目名称为getting-started。
Linux & MacOS
mvn io.quarkus.platform:quarkus-maven-plugin:2.6.2.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=getting-started \
-DclassName="org.acme.getting.started.GreetingResource" \
-Dpath="/hello"
Windows
cmd
mvn io.quarkus.platform:quarkus-maven-plugin:2.6.2.Final:create -DprojectGroupId=org.acme -DprojectArtifactId=getting-started -DclassName="org.acme.getting.started.GreetingResource" -Dpath="/hello"
powershell
mvn io.quarkus.platform:quarkus-maven-plugin:2.6.2.Final:create "-DprojectGroupId=org.acme" "-DprojectArtifactId=getting-started" "-DclassName=org.acme.getting.started.GreetingResource" "-Dpath=/hello"
使用web页面创建
使用web页面:访问通过网站:https://code.quarkus.io,这种方法类似于spring.io提供的web页面
使用IDEA创建
使用IDEA,这里不得不说IDEA的强大,其实也是去加载https://code.quarkus.ioweb资源。
-
运行应用
GraalVM运行
项目创建后通过IDEA打开加载相关依赖启动项目,在项目根目录下,执行命令启动
./mvnw compile quarkus:dev:
或者
mvn quarkus:dev
成功启动应用后,查看控制台输出 ```bash Listening for transport dt_socket at address: 5005
—/ \/ / / / | / \/ //_/ / / / / -/ // / // / |/ , / ,< / // /\ \ —___// |//|//||_/_/ 2022-01-20 14:38:01,336 INFO [io.quarkus] (Quarkus Main Thread) getting-started 1.0.0-SNAPSHOT on JVM (powered by Quarkus 2.6.2.Final) started in 3.635s. Listening on: http://localhost:8080
2022-01-20 14:38:01,347 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. 2022-01-20 14:38:01,348 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy, smallrye-context-propagation, vertx]
通过地址访问 [http://localhost:8080](http://localhost:8080),Quarkus提供了一个Dev UI。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2456868/1642660609355-c8a31b37-5bb1-4556-8695-2eee59ee53e3.png#clientId=u63fc7ad5-4d70-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=749&id=uefd2a65e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=936&originWidth=1853&originalType=binary&ratio=1&rotation=0&showTitle=false&size=137925&status=done&style=none&taskId=uda10b7eb-9b5e-4970-8860-f040048ef66&title=&width=1482.4)
> 如果配置文件引入了数据库相关驱动,却没有指定可用的jdbc配置信息,启动项目会要求有可用的docker环境,自动创建docker镜像并运行,这也说明了quarkus对云原生的良好支持。
```bash
/opt/develop/graalvm-ce-java11-21.3.0/bin/java -Dmaven.multiModuleProjectDirectory=/home/starsray -Dmaven.home=/opt/ideaIU-2021.2.3/plugins/maven/lib/maven3 -Dclassworlds.conf=/opt/ideaIU-2021.2.3/plugins/maven/lib/maven3/bin/m2.conf -javaagent:/opt/ideaIU-2021.2.3/lib/idea_rt.jar=43095:/opt/ideaIU-2021.2.3/bin -Dfile.encoding=UTF-8 -classpath /opt/ideaIU-2021.2.3/plugins/maven/lib/maven3/boot/plexus-classworlds.license:/opt/ideaIU-2021.2.3/plugins/maven/lib/maven3/boot/plexus-classworlds-2.6.0.jar org.codehaus.classworlds.Launcher -Didea.version=2021.2.3 -DskipTests=true quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< cn.starsray:quarkus-web >-----------------------
[INFO] Building quarkus-web 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- quarkus-maven-plugin:2.6.2.Final:dev (default-cli) @ quarkus-web ---
[INFO] Invoking org.apache.maven.plugins:maven-resources-plugin:2.6:resources) @ quarkus-web
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Invoking io.quarkus.platform:quarkus-maven-plugin:2.6.2.Final:generate-code) @ quarkus-web
[INFO] Invoking org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile) @ quarkus-web
[INFO] Nothing to compile - all classes are up to date
[INFO] Invoking org.apache.maven.plugins:maven-resources-plugin:2.6:testResources) @ quarkus-web
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/starsray/IdeaProjects/quarkus-web/quarkus-web/src/test/resources
[INFO] Invoking io.quarkus.platform:quarkus-maven-plugin:2.6.2.Final:generate-code-tests) @ quarkus-web
[INFO] Invoking org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile) @ quarkus-web
[INFO] Nothing to compile - all classes are up to date
Listening for transport dt_socket at address: 5005
Press [h] for more options>
Tests paused
Press [r] to resume testing, [h] for more options>
Press [r] to resume testing, [o] Toggle test output, [h] for more options>
2022-01-16 23:25:11,416 INFO [org.tes.doc.DockerClientProviderStrategy] (build-37) Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2022-01-16 23:25:11,888 INFO [org.tes.doc.DockerClientProviderStrategy] (build-37) Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
2022-01-16 23:25:11,890 INFO [org.tes.DockerClientFactory] (build-37) Docker host IP address is localhost
2022-01-16 23:25:11,935 INFO [org.tes.DockerClientFactory] (build-37) Connected to docker:
Server Version: 19.03.8
API Version: 1.40
Operating System: UnionTech OS Desktop 20 Home
Total Memory: 15688 MB
2022-01-16 23:25:11,938 INFO [org.tes.uti.ImageNameSubstitutor] (build-37) Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2022-01-16 23:25:12,005 INFO [org.tes.uti.RegistryAuthLocator] (build-37) Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: testcontainers/ryuk:0.3.3, configFile: /home/starsray/.docker/config.json. Falling back to docker-java default behaviour. Exception message: /home/starsray/.docker/config.json (没有那个文件或目录)
2022-01-16 23:25:12,676 INFO [org.tes.DockerClientFactory] (build-37) Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2022-01-16 23:25:12,676 INFO [org.tes.DockerClientFactory] (build-37) Checking the system...
2022-01-16 23:25:12,677 INFO [org.tes.DockerClientFactory] (build-37) ✔︎ Docker server version should be at least 1.6.0
2022-01-16 23:25:12,755 INFO [org.tes.DockerClientFactory] (build-37) ✔︎ Docker environment should have more than 2GB free disk space
2022-01-16 23:25:12,780 INFO [🐳 .io/.0.24]] (build-37) Creating container for image: docker.io/mysql:8.0.24
2022-01-16 23:25:12,781 INFO [org.tes.uti.RegistryAuthLocator] (build-37) Failure when attempting to lookup auth config. Please ignore if you don't have images in an authenticated registry. Details: (dockerImageName: docker.io/mysql:8.0.24, configFile: /home/starsray/.docker/config.json. Falling back to docker-java default behaviour. Exception message: /home/starsray/.docker/config.json (没有那个文件或目录)
2022-01-16 23:25:12,874 INFO [🐳 .io/.0.24]] (build-37) Starting container with ID: ec24cbadb7cdd72ce95cbdcb01011173939705e4c7685c070074fa7c0fbb270e
2022-01-16 23:25:13,122 INFO [🐳 .io/.0.24]] (build-37) Container docker.io/mysql:8.0.24 is starting: ec24cbadb7cdd72ce95cbdcb01011173939705e4c7685c070074fa7c0fbb270e
2022-01-16 23:25:13,131 INFO [🐳 .io/.0.24]] (build-37) Waiting for database connection to become available at jdbc:mysql://localhost:32773/default using query 'SELECT 1'
2022-01-16 23:25:26,498 INFO [🐳 .io/.0.24]] (build-37) Container is started (JDBC URL: jdbc:mysql://localhost:32773/default)
2022-01-16 23:25:26,499 INFO [🐳 .io/.0.24]] (build-37) Container docker.io/mysql:8.0.24 started in PT13.732728S
2022-01-16 23:25:26,499 INFO [io.qua.dev.mys.dep.MySQLDevServicesProcessor] (build-37) Dev Services for MySQL started.
2022-01-16 23:25:26,500 INFO [io.qua.dat.dep.dev.DevServicesDatasourceProcessor] (build-37) Dev Services for the default datasource (mysql) started.
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-01-16 23:25:27,968 ERROR [io.qua.hib.orm.run.sch.SchemaManagementIntegrator] (Hibernate post-boot validation thread for <default>) Failed to validate Schema: Schema-validation: missing table [employee]
2022-01-16 23:25:27,979 ERROR [io.qua.hib.orm.run.sch.SchemaManagementIntegrator] (Hibernate post-boot validation thread for <default>) The following SQL may resolve the database issues, as generated by the Hibernate schema migration tool. WARNING: You must manually verify this SQL is correct, this is a best effort guess, do not copy/paste it without verifying that it does what you expect.
create table employee (emp_no integer not null, birth_date date not null, first_name varchar(14) not null, gender char(1) not null, hire_date date not null, last_name varchar(16) not null, primary key (emp_no)) engine=InnoDB;
2022-01-16 23:25:28,003 INFO [io.quarkus] (Quarkus Main Thread) quarkus-web 1.0.0-SNAPSHOT on JVM (powered by Quarkus 2.6.2.Final) started in 17.707s. Listening on: http://localhost:8080
2022-01-16 23:25:28,006 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2022-01-16 23:25:28,006 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, config-yaml, hibernate-orm, hibernate-orm-panache, jdbc-mysql, mybatis, mybatis-plus, narayana-jta, reactive-mysql-client, rest-client, rest-client-jackson, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-openapi, swagger-ui, vertx]
可以看到在启动过程中创建了Docker容器,并且互通两个容器。
Native Image运行
这也是quarkus最强大的地方,通过GraalVM的可选组件native image可以将Java应用打包成原生镜像,真正做到秒级启动,解决了传统spring启动的痛点,当然也期待spring的下一代产品Spring Native。
使用命令安装native支持
sudo gu install native-image
打包项目
mvn package -Pnative -DskipTests
启动 做到了秒启动。
注意事项
启动编译失败
如果本地存在多个JDK版本,项目启动编译失败,请确保Java和Maven的版本是否正确,正确配置后重启IDEA。
java
$ java -version
openjdk version "11.0.13" 2021-10-19
OpenJDK Runtime Environment GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.3.0 (build 11.0.13+7-jvmci-21.3-b05, mixed mode, sharing)
maven
$ mvn -v
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: D:\maven\apache-maven-3.8.4
Java version: 11.0.13, vendor: GraalVM Community, runtime: C:\Program Files\Java\graalvm-ce-java11-21.3.0
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
windows native build
native image需要先打包native可执行文件,我这里使用的是Linux环境,所以打包没什么问题,在Windows环境下打包始终不能成功,参考官方文档也一直未能成功打包,可能跟我使用的Windows11环境有关,有兴趣的小伙伴可以自己试试。
介绍
对比Spring应用,Quarkus应用在目录结构上并没有太大不同,主要是一些依赖实现的区别。Spring针对JavaEE规范有一套自己的实现,Quarkus整合了多个优秀的开源框架实现,类似于Spring Cloud对微服务组件的整合。Quarkus主要整合了以下常用组件,有兴趣的可以单独了解
- SmallRye
- Hibernate
- Netty
- RESTEasy
- Apache Camel
- Eclipse MicroProfile
在getting-started项目中主要了解以下三方面内容
- pom文件
- REST Resource
Bean
Quarkus项目目录树结构
├─.idea
├─.mvn
│ └─wrapper
├─src
│ ├─main
│ │ ├─docker
│ │ ├─java
│ │ │ └─org
│ │ │ └─acme
│ │ │ └─getting
│ │ │ └─started
│ │ └─resources
│ │ └─META-INF
│ │ └─resources
│ └─test
│ └─java
│ └─org
│ └─acme
│ └─getting
│ └─started
└─target
└─classes
└─META-INF
└─resources
pom.xml
在pom.xml中默认依赖了Quarkus的BOM清单,在
中做了关于Quarkus的统一版本管理,类似于spring-boot-dependencies的功能。 <dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
pom.xml中还添加了打包相关的插件,使用quarkus-maven-plugin来进行打包、启动、native image等操作。
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
其中quarkus-resteasy是REST应用的依赖
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
其他依赖
quarkus-smallrye-openapi openapi实现引入支持swagger-ui
- quarkus-mybatis/quarkus-mybatis-plus mybatis及mybatis-plus组件
- quarkus-hibernate-orm-panache hibernate JPA实现
- quarkus-config-yaml yaml语法配置文件相关依赖
- quarkus-reactive-mysql-client mysql客户端依赖
- quarkus-jdbc-mysql mysql JDBC驱动依赖
- quarkus-resteasy-jackson rest接口依赖
REST Resource
项目中默认生成了GreetingResource一个REST资源类 ```java package org.acme.getting.started;
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType;
@Path(“/hello”) public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello RESTEasy";
}
}
@Path、@GET、@Produces都是基于JAX-RS规范实现的注解。在Spring盛行的今天,JavaWeb方向国内几乎人人都是Spring程序员,对于JavaEE的规范了解使用都不多。<br />JAX-RS是JAVA EE6引入的一个新技术,英文全称为Java API for RESTful Web Services,它的核心概念是面向资源,即Resource形式,常见的实现有Jersey、RESTEasy,就好比JPA的实现Hibernate。<br />关于JAX-RS参考:[https://cloud.tencent.com/developer/article/1600752](https://cloud.tencent.com/developer/article/1600752)
<a name="CAVZe"></a>
## Bean
Spring核心的功能就是IoC和DI,DI是指依赖注入,Quarkus中依赖注入使用了ArC,ArC是JavaEE规范中的CDI的一个实现,是Quarkus定制化的依赖注入组件。<br />CDI全称Contexts and Dependency Injection,即上下文依赖注入,JEE众多规范中的一个,从JavaEE开始CDI成为正式规范。CDI参考文档:
- [Java EE CDI Dependency Injection (@Inject) tutorial](http://www.byteslounge.com/tutorials/java-ee-cdi-dependency-injection-inject-tutorial)
- [Java EE CDI Producer methods tutorial](http://www.byteslounge.com/tutorials/java-ee-cdi-producer-methods-tutorial)
- [Java EE CDI bean scopes](http://www.byteslounge.com/tutorials/cdi-bean-scopes)
Quarkus CDI参考文档:[https://quarkus.io/guides/cdi](https://quarkus.io/guides/cdi)<br />通过CDI来初始化一个被容器管理的Bean时候都会指定Bean的生命周期,在Spring中指定的Bean默认都是单例的,生命周期通过@Scope注解来修改。<br />CDI提供了提供了一系列注解,根据注解名称就能看出修饰Bean生命周期。
- @ApplicationScoped
- @SessionScoped
- @RequestScoped
- @ConversationScoped
在Quarkus中不需要指定创建Application级别的类,一般也不需要特定标注Bean的生命周期。
> With Quarkus, there is no need to create an Application class. It’s supported, but not required. In addition, only one instance of the resource is created and not one per request. You can configure this using the different *Scoped annotations (ApplicationScoped, RequestScoped, etc)
Quarkus同样支持类似于Spring中Controller注入Service的形式,新增一个GreetingService类
```java
package org.acme.getting.started;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
修改GreetResource类,并注入GreetingService类
package org.acme.getting.started;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.annotations.jaxrs.PathParam;
@Path("/hello")
public class GreetingResource {
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(@PathParam String name) {
return service.greeting(name);
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
开发
Development Mode
通过quarkus:dev命令会使应用在开发模式启动,可以对pom.xml、Java类、Resouce目录下的变动进行热加载,减少重启,这大大加快了开发调试效率。
debug模式会默认监听5005端口,如果想要在项目启动前进入调试模式通过命令行指定 -Dsuspend,也可以通过-Ddebug=false跳过所有调试。
Testing
在生成的pom.xml文件中默认引入了test依赖和相关打包插件
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
创建的项目中默认包含了一个测试类GreetingResourceTest
package org.acme.getting.started;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import java.util.UUID;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("hello"));
}
@Test
public void testGreetingEndpoint() {
String uuid = UUID.randomUUID().toString();
given()
.pathParam("name", uuid)
.when().get("/hello/greeting/{name}")
.then()
.statusCode(200)
.body(is("hello " + uuid));
}
}
类似于SpringBootRunner,Quarkus使用QuarkusTest runner来运行,校验返回结果。
Package
项目打包可以使以下命令,打包后的可执行jar或者native-image在./target目录。
- ./mvnw package & mvn package
mvn package -Pnative -DskipTests(打包native)
其他
banner
Quarkus也提供了类似于SpringBoot banner的功能。
禁用banner
- quarkus.banner.enabled=false (application.properties)
- -Dquarkus.banner.enabled=false(Java System Property)
- QUARKUS_BANNER_ENABLED=false (ENV)
- 自定义banner,添加文件到src/main/resources目录,在application.properties中指定文件路径
- quarkus.banner.path=name-of-file
Spring对比
注解相关说明:
Spring中有一套自己针对相关功能的注解实现,Quarkus也有自己的整合实现,列举相关的对应关系。
DI —> CDI
Spring Web —> JAX-RS
Spring Data JPA —> Panache
Swagger/Knife —> OpenAPI源码
https://gitee.com/starsray/quarkus
- quarkus.banner.path=name-of-file