返回顶部

《Quarkus实战》总结

一、优势

  1. 占用内容小,启动速度快,只要几分之一秒,可以在k8s部署尽可能多的实例,快速运行
  2. 开发热部署,边改代码直接生效

二、搭建脚手架

命令方式创建

mvn io.quarkus:quarkus-maven-plugin:1.4.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=getting-started\
-DclassName="org.acme.quickstart.GreetingResource" \
-Dpath="/hello"

目录结构

开发模式实时重载

mvn compile quarkus:dev

三、Rest

// 获取请求的Uri信息
@Context UriInfo uriInfo,
@QueryParam("order") String order,
@HeaderParam("token") String token
// 获取表单参数
@FormParam
// 矩阵参数
@MatrixParam
@CookieParam

1)启用跨源资源共享

使用quarkus.http.cors配置属性来启用跨源资源共享(CORS)。

quarkus.http.cors=true
quarkus.http.cors.origins=http://example.com
quarkus.http.cors.methods=GET,PUT,POST,DELETE
quarkus.http.cors.headers=accept,authorization,content-type,x-requested-with

2)拦截HTTP请求

使用io.quarkus.vertx.http.runtime.filters.Filters,继承ContainerResponseFilter

@Provider
public class HeaderAdditionContainerResponseFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        responseContext.setEntity("haha-A");
    }
}

3)使用SSL进行安全连接

quarkus.http.ssl-port=8443
quarkus.http.ssl.certificate.key-store-file=keystore.jks
quarkus.http.ssl.certificate.key-store-file-type=jks
quarkus.http.ssl.certificate.key-store-password=changeit

四、配置

application.properties文件中定义

@ConfigProperty(name = "quarkus.mailer.from")
String from;

1)以程序化的方式访问配置属性

注入org.eclipse.microprofile.config.Config来程序化地获取属性值

2)在外部覆盖配置值

Quarkus允许你通过将配置设置为系统属性(-Dproperty.name=value)或环境变量(export PROPERTY_NAME=value)来覆盖任何配置属性。系统属性比环境变 量有更高的优先级。

举例:

3)修改日志配置

只需修改quarkus.log.level设置

quarkus.log.level=DEBUG

限制类的日志级别

五、编程模型

1)校验输入值和输出值

使用Bean Validation规范来为模型添加校验。

mvn quarkus:add-extension -Dextensions="quarkus-hibernate-validator"

2)全局异常处理

继承javax.ws.rs.ext.ExceptionMapper

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class BeanValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
    @Override
    public Response toResponse(ConstraintViolationException exception) {
        return Response.status(Response.Status.BAD_REQUEST)
                .entity(createErrorMessage(exception))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }

    private JsonArray createErrorMessage(ConstraintViolationException exc) {
        JsonArrayBuilder errors = Json.createArrayBuilder();
        for (ConstraintViolation<?> violation : exc.getConstraintViolations()) {
            errors.add(
                    Json.createObjectBuilder()
                            .add("path", violation.getPropertyPath().toString())
                            .add("message", violation.getMessage())
            );
        }
        return errors.build();
    }
}

3)创建自定义校验

实现javax.validation.ConstraintValidator接口和注解

最后使用方式

4)以程序化的方式校验对象

使用Bean Validation javax.validation.Validator

5)依赖注入

使用@Inject


6)创建工厂类

使用javax.enterise.inject.Produces允许创建任何类型的对象,等同于Spring中@Bean

使用@io.quarkus.arc.DefaultBean表示默认对象,等同Spring中@Default

7)如何在创建或销毁对象前后执行一些逻辑

使用@javax.annotation.PostConstruct和 @javax.annotation.PreDestroy注解进行对象生命周期管理。对于 PostConstruct来说,使用这些注解的方法将在对象创建之后被调用;对 于PreDestroy来说,使用这些注解的方法在对象被销毁之前被调用:

比较类似Spring

8)如何在应用程序启动或关闭后执行一些逻辑?

io.quarkus.runtime.StartupEvent和io.quarkus.runtime.ShutdownEvent事件:在应用程序启动时,Quarkus会产生StartupEvent事件;而在关闭时,会产生ShutdownEvent事件

9)如何用名字限定一个注解?

使用@javax.inspit.Named注解

它的值并不是必需的,但是在没有实际名字的情况下使用@Named是没有意义的。当解析一个注解时,CDI将寻找任何同样包含相同限定符的正确类型的bean。在有@Named的情况下,注解的值部分也必须匹配。

10)如何使用注解来限定和配置依赖?

使用producer中的InjectionPoint和限定符注解上的非绑定属性的组合,可以同时限定和配置一个bean。

使用

11)创建拦截器

创建@javax.init.AroundInvoke@javax.init.AroundConstruct两个具有相应拦截绑定功能的拦截器。你还需要创建CDI,以便将拦截器编译组合到一个注解中。

首先,使用@javax.interceptor.InterceptorBinding创建一个注解,这将被用来关联实际的拦截器代码,并对任何你希望被拦截的方法或类进行注解:

@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LogEvent {
}
@LogEvent
@Interceptor
@Slf4j
public class LogEventInterceptor {

    @AroundInvoke
    public Object logEvent(InvocationContext ctx) throws Exception {
        log.info("method:{}", ctx.getMethod().getName());
        return ctx.proceed();
    }
}

最后把注解@LogEvent放到需要的方法上面就可以成功执行

12)测试端口

通过配置quarkus.http.test-port改变测试端口,为0表示随机端口

13)单元测试

推荐使用AssertJ,依赖

  <dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <scope>test</scope>
  </dependency>

记得添加quarkus-hibernate-validator扩展

@ApplicationScoped
public class HelloService {
    public String greeting(@Length(min = 6) String message) {
        return "say:" + message;
    }
}

测试方法如下

@QuarkusTest
class HelloServiceTest {

    @Inject
    HelloService helloService;
    @Test
    void greeting1() {
        Assertions.assertThatExceptionOfType(ConstraintViolationException.class)
                .isThrownBy(()-> helloService.greeting("hello"));
    }
    @Test
    void greeting2() {
        String message = helloService.greeting("hello man");
        Assertions.assertThat(message).isEqualTo("say:hello man");
    }
}

14)使用Mockito创建mock对象

引入pom

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-junit5-mockito</artifactId>
  <scope>test</scope>
</dependency>

15)元注解

再将这个注解应用到一个类上,也就是意味着你同时应用了@QuarkusTest@Transactional注解:

16)在测试代码前后执行代码

继承io.quarkus.test.common.QuarkusTestResourceLifecycleManager

public class DefaultQuarkusTestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager {
    @Override
    public Map<String, String> start() {
        System.out.println("lifecycle start");
        return Collections.emptyMap();
    }

    @Override
    public void stop() {
        System.out.println("lifecycle stop");
    }

    @Override
    public void inject(Object testInstance) {
        System.out.println("executing "+testInstance.getClass().getName());
    }

    @Override
    public int order() {
        return 0;
    }
}
@QuarkusTest
@QuarkusTestResource(DefaultQuarkusTestResourceLifecycleManager.class)
public class HelloResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("hello"));
    }

}

❶在Quarkus启动前调用start方法

❷在HelloResourceTest运行前调用inject方法

❸在所有测试执行完毕后调用stop方法

六、打包Quarkus应用程序

  1. 在JVM中运行应用程序

    mvn clean package 打包应用

    执行java -jar target/hello-1.0-runner.jar 即可

  2. 若要把lib包的依赖都打到一个jar包中去,只需配置

    quarkus.package.uber-jar=true
    

七、持久化

1)配置数据源

quarkus:
  datasource:
    jdbc:
      url: jdbc:mysql://mysql.ops.svc.cluster.local:3306/seedserver_dev?autoReconnect=true&useUnicode=true&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&serverTimezone=GMT%2b8
    username: root
    password: root
    db-kind: mysql

2)配置多数据源

quarkus:
  datasource:
    dev:
      jdbc:
        url: jdbc:mysql://mysql.ops.svc.cluster.local:3306/seedserver_dev?autoReconnect=true&useUnicode=true&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&serverTimezone=GMT%2b8
      username: root
      password: root
      db-kind: mysql
    test:
      jdbc:
        url: jdbc:mysql://mysql.ops.svc.cluster.local:3306/seedserver_test?autoReconnect=true&useUnicode=true&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&serverTimezone=GMT%2b8
      username: root
      password: root
      db-kind: mysql

测试代码

import io.agroal.api.AgroalDataSource;
import io.quarkus.agroal.DataSource;
import io.quarkus.test.junit.QuarkusTest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import javax.inject.Inject;
import java.sql.Connection;
import java.sql.SQLException;


@QuarkusTest
class DataSourceServiceTest {

    @Inject
    @DataSource(value = "test")
    AgroalDataSource devDataSource;

    @Test
    void printDev() throws SQLException {
        Connection connection = devDataSource.getConnection();
        Assertions.assertThat(connection.getCatalog()).isEqualTo("seedserver_test");
    }
}

3)事务定义

使用quarkus-narayana-jta扩展添加了@javax.transaction.Transactional注解以及TransactionManager和UserTransaction

4)设置事务的上下文

  • @Transactional(REQUIRED)(默认)

    如果没有启动事务,则启动;否则,保持现有的事务。

  • @Transactional(REQUIRES_NEW)

    如果没有启动事务,则启动;如果已经启动了一个现有的事务,则

    暂停该事务,并在该方法的结尾启动一个新的事务。

  • @Transactional(MANDATORY)

    如果没有启动事务,则失败;否则,使用现有的事务。

  • @Transactional(SUPPORTS)

    如果一个事务已经开始,则加入它;否则,以无事务的方式工作。

  • @Transactional(NOT_SUPPORTED)

    如果一个事务被启动,则暂停它,并在方法的结尾以无事务的方式

    工作;否则,以无事务的方式工作。

  • @Transactional(NEVER)

    如果一个事务被启动,则抛出一个异常;否则,以无事务的方式工

    作。

5)用Panache持久化数据

调用PanacheEntity中的persist方法。

当然,你需要添加quarkus-hibernate-orm-panache扩展,并为你的数据存储添加相应的JDBC扩展。接下来,你需要定义一个实体,也就是需要创建一个类,用@javax.persistence.Entity注解它,并基于PanacheEntity进行扩展。

简单例子:

@Entity
public class FruitEntity extends PanacheEntity {

    @Column(length = 40, unique = true)
    public String name;

    public FruitEntity() {
    }

    public FruitEntity(String name) {
        this.name = name;
    }
}
@Path("entity/fruits")
@ApplicationScoped
@Produces("application/json")
@Consumes("application/json")
public class FruitEntityResource {
    @POST
    @Transactional
    public Response create(FruitEntity fruit) {
        if (fruit.id != null) {
            throw new WebApplicationException("Id was invalidly set on request.", 422);
        }
        // 持久化
        fruit.persist();
        return Response.ok(fruit).status(201).build();
    }
}

6)更多Panache方法

FruitEntity.listAll();
FruitEntity.findById()
FruitEntity.find(HQL语句)
FruitEntity.list()
FruitEntity.count(HQL语句)

7)用Panache连接mongo

添加pom

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-mongodb-panache</artifactId>
</dependency>

用法类似db

八、容错

1)自动重试

添加

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-fault-tolerance</artifactId>
</dependency>

简单例子,重试3次,执行错误结果

@ApplicationScoped
public class HelloService {

    @Retry(maxRetries = 3)
    @Fallback(FailCallback.class)
    public String greeting(@Length(min = 6) String message) {
        System.out.println("enter greeting");
        if (message.length() == 7) {
            throw new RuntimeException("错误7");
        }
        return "say:" + message;
    }

    public static class FailCallback implements FallbackHandler<String>{
        @Override
        public String handle(ExecutionContext executionContext) {
            return "fail handle";
        }
    }
}
@QuarkusTest
class HelloServiceTest {

    @Inject
    HelloService helloService;

    @Test
    void greeting2() {
        String message = helloService.greeting("hello m");
        Assertions.assertThat(message).isEqualTo("fail handle");
    }
}

执行结果

可以通过配置参数的形式进行方法或全局的属性配置

fully_qualified_class_name/method_name/fault_tolerant_annotation/parameter

例如:

# 全局级别
/Retry/delay: 3000
# 或方法级别
com:
  lll:
    component:
      HelloService/greeting/Retry/delay: 3000

# 或类级别
com:
  lll:
    component:
      HelloService/Retry/delay: 3000

当类级别的配置的时候,@Retry注解也需要在类上,否则仅类中方法标注该注解无效

2)超时

@org.eclipse.microprofile.faultttoler ance.Timeout注解类或方法

    @Timeout(value = 1000)
    public String hello(String message) throws InterruptedException {
        System.out.println("enter hello");
        TimeUnit.SECONDS.sleep(2);
        return "say:" + message;
    }
    @Test
    void hello() throws InterruptedException {
        helloService.hello("hello");
    }

结果

enter hello

org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException: com.lll.component.HelloService#hello timed out

3)过载保护

如何限制并发请求数?

@org.eclipse.microprofile.faultttolerance.Bulkhead注解的类或方法

例子:

    @Bulkhead(2)
    public String hello(String message) throws InterruptedException {
        System.out.println("enter hello");
        TimeUnit.SECONDS.sleep(2);
        return "say:" + message;
    }
   @Test
    void hello() throws InterruptedException {
        List<CompletableFuture> futures = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    helloService.hello("hello");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            futures.add(future);
        }
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    }

结果

enter hello
enter hello

java.util.concurrent.CompletionException: org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException: com.lll.component.HelloService#hello rejected from bulkhead

  at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
  at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
  at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1807)
  at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796)
  at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
  at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
  at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
  at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
  at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException: com.lll.component.HelloService#hello rejected from bulkhead
  at io.smallrye.faulttolerance.core.bulkhead.BulkheadBase.bulkheadRejected(BulkheadBase.java:17)

并发数为2,同时到达的其它两个请求就会被拒绝

同样的和重试一样,它也支持全局属性配置

# 全局级别
/Bulkhead/value: 10
# 或方法级别
com:
  lll:
    component:
      HelloService/greeting/Bulkhead/value: 10

# 或类级别
com:
  lll:
    component:
      HelloService/Bulkhead/value: 10

4)断路器

@org.eclipse.microprofile.faulttolerance.CircuitBreaker注解的类或方法

    @CircuitBreaker(requestVolumeThreshold = 5, failureRatio = 0.6, delay = 2000)
    public String helloCircuit(String message) throws InterruptedException {
        System.out.println("enter hello");
        TimeUnit.MILLISECONDS.sleep(100);
        if (RandomUtils.nextInt(1, 5) <= 2) {
            System.out.println("enter fail");
            throw new RuntimeException("hello fail");
        }
        return "say:" + message;
    }

表示5个请求失败3个则断路保护,延迟2秒后恢复

HTTP Request to /hello/helloCircuit?text=helloCircuit failed, error id: 56145d9f-d726-4de1-a6af-057390cb74ff-20: org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException: com.lll.component.HelloService#helloCircuit circuit breaker is half-open

5)禁用容错

类似自动重试配置

# 或方法级别
com:
  lll:
    component:
      HelloService/greeting/CircuitBreaker/enabled: false

# 或类级别
com:
  lll:
    component:
      HelloService/CircuitBreaker/enabled: false
# 全局级别
CircuitBreaker/enabled: false

# 禁用所有容错
MP_Fault_Tolerance_NonFallback_Enabled: false

九、可观察性

1)健康检查

引入pom

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-health</artifactId>
</dependency>

{
    "status": "UP",
    "checks": [
        {
            "name": "Database connections health check",
            "status": "UP",
            "data": {
                "<default>": "UP"
            }
        }
    ]
}

2)自定义健康检查

通过创建一个注解为@org.eclipse.microprofile.health.Liveness@org.eclipse.microprofile.health.Readiness的方法来创建自定义健康检查

3)暴露服务指标

引入

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-metrics</artifactId>
    </dependency>

调用

curl --header "Accept:application/json" localhost:8080/q/metrics

结果

{
    "base": {
        "cpu.systemLoadAverage": 6.673828125,
        "thread.count": 30,
        "classloader.loadedClasses.count": 16004,
        "classloader.unloadedClasses.total": 7,
        "gc.total;name=G1 Young Generation": 14,
        "jvm.uptime": 162059,
        "thread.max.count": 62,
        "memory.committedHeap": 566231040,
        "classloader.loadedClasses.total": 16011,
        "cpu.availableProcessors": 8,
        "thread.daemon.count": 20,
        "gc.total;name=G1 Old Generation": 0,
        "memory.maxHeap": 4294967296,
        "cpu.processCpuLoad": 0.0003392775819228651,
        "gc.time;name=G1 Old Generation": 0,
        "memory.usedHeap": 295558848,
        "gc.time;name=G1 Young Generation": 190
    },
    "vendor": {
        "memoryPool.usage.max;name=G1 Survivor Space": 21979920,
        "memory.freePhysicalSize": 91815936,
        "memoryPool.usage.max;name=CodeHeap 'non-profiled nmethods'": 3972608,
        "memoryPool.usage;name=Metaspace": 83864016,
        "memoryPool.usage;name=G1 Eden Space": 0,
        "memoryPool.usage;name=CodeHeap 'non-profiled nmethods'": 3642880,
        "memoryPool.usage;name=CodeHeap 'profiled nmethods'": 19791104,
        "memoryPool.usage;name=G1 Old Gen": 160471552,
        "memoryPool.usage.max;name=CodeHeap 'non-nmethods'": 1449856,
        "memoryPool.usage.max;name=G1 Old Gen": 160471552,
        "cpu.processCpuTime": 14605324000,
        "memory.committedNonHeap": 123207680,
        "memoryPool.usage.max;name=Compressed Class Space": 10443936,
        "memoryPool.usage.max;name=G1 Eden Space": 285212672,
        "memory.freeSwapSize": 1312292864,
        "memoryPool.usage.max;name=Metaspace": 83863688,
        "cpu.systemCpuLoad": 0.315098789643286,
        "memory.usedNonHeap": 119182168,
        "memoryPool.usage;name=CodeHeap 'non-nmethods'": 1439616,
        "memoryPool.usage;name=G1 Survivor Space": 869568,
        "memoryPool.usage;name=Compressed Class Space": 10443936,
        "memory.maxNonHeap": -1,
        "memoryPool.usage.max;name=CodeHeap 'profiled nmethods'": 21394432
    },
    "application": {
    }
}
  • base

    服务器的核心信息。这些指标总是必需的,因为它们在规范中被指定。可在/metrics/base访问它们。

  • vendor

    供应商的具体信息。每个实施方案可能会提供不同的信息。可在/metrics/vendor访问它们。

  • application

    使用MicroProfile Metrics扩展机制为该服务专门开发的自定义信息。可在/metrics/application访问它们。

4)创建指标

@Counted计数器,用来记录方法执行次数

@Gauge用来查询自定义指标

@Metered用来查询方法调用速度

@Timed用来记录方法调用时长

综合案例

    @Timed(name = "checksTimer", description = "A measure how long it takes to perform the primality test.", unit = MetricUnits.MILLISECONDS)
    @Metered(name = "helloMetered")
    @Counted(name = "performedChecks", description = "How many primality checks have been performed.")
    public String helloCircuit(String message) throws InterruptedException {
        System.out.println("enter hello");
        return "say:" + message;
    }
    @Gauge(name = "highestPrimeNumberSoFar", unit = MetricUnits.NONE, description = "Highest prime number so far.")
    public Long getLong() throws InterruptedException {
        System.out.println("enter getLong");
        return RandomUtils.nextLong();
    }
    @GET
    @Path("/helloCircuit")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Result helloCircle(@QueryParam("text") String text) throws InterruptedException {
        helloService.getLong();
        return Result.<String>ok(helloService.helloCircuit(text));
    }

调用localhost:8080/helloCircuit多次后执行

curl --header "Accept:application/json" localhost:8080/q/metrics/application

结果

{
    "com.lll.component.HelloService.helloMetered": {
        "fiveMinRate": 0.8838044191690506,
        "fifteenMinRate": 1.523369957905502,
        "meanRate": 0.03955995332301929,
        "count": 10,
        "oneMinRate": 0.0337024025198951
    },
    "com.lll.component.HelloService.checksTimer": {
        "p99": 102.830667,
        "min": 0.152542,
        "max": 102.830667,
        "mean": 50.73874038036284,
        "p50": 0.96975,
        "p999": 102.830667,
        "stddev": 50.675931154849316,
        "p95": 102.830667,
        "p98": 102.830667,
        "p75": 101.428083,
        "fiveMinRate": 0.8838044191690506,
        "fifteenMinRate": 1.523369957905502,
        "meanRate": 0.03955965314051408,
        "count": 10,
        "oneMinRate": 0.0337024025198951,
        "elapsedTime": 510.434292
    },
    "com.lll.component.HelloService.highestPrimeNumberSoFar": 3072960605013709814,
    "com.lll.component.HelloService.performedChecks": 10
}

5)分布式链路追踪

参考官网OpenTracing jaeger

十、认证和授权

1)使用Elytron Security JDBC配置进行认证授权

首先加入pom

mvn quarkus:add-extension -Dextensions="quarkus-elytron-security-jdbc,quarkus-jdbc-mysql"

配置

quarkus:
  security:
    jdbc:
      enabled: true
      principal-query:
        sql: select u.password,u.role from test_user u where u.username=?
        clear-password-mapper:
          enabled: true
          password-index: 1
        attribute-mappings:
          0:
            index: 2
            to: groups

@Path("/hello")
@RolesAllowed("Tester")
public String hello(@Size(min = 5, max = 10) @QueryParam("text") String text) {
    return "hello";
}

调用localhost:8080/hello需要认证

输入数据库用户名密码通过

以上为明文密码,实际生成需要使用加密配置

Quarkus还提供了jwt加密,openId加密方式等具体详看文末链接

十一、使用Spring API开发Quarkus

1)Spring依赖注入

引入包

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-spring-di</artifactId>
    </dependency>

以下注解等价可替换

2)Spring Web

引入包

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-spring-web</artifactId>
    </dependency>
com.lll.component.HelloService;
import com.lll.entity.Result;
import com.lll.intercept.LogEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.Size;
import javax.ws.rs.QueryParam;

@RestController
@RequestMapping("/hello2")
public class HelloSpringResource {

    @Autowired
    HelloService helloService;

    @GetMapping
    public String hello(@Size(min = 5, max = 10) @QueryParam("text") String text) {
        Person person = new Person();
        person.setName(text);
        return text;
    }

    @GetMapping("/helloCircuit")
    public Result helloCircle(@QueryParam("text") String text) throws InterruptedException {
        helloService.getLong();
        return Result.<String>ok(helloService.helloCircuit(text));
    }
}

和Spring用法一致

还有Spring的JPA、security、config兼容等等,感兴趣可以看看

十二、Quarkus附加功能

  1. 模板引擎Qute,提供创建模板的功能
  2. 发送电子邮件mailer扩展
  3. 调度任务scheduler
  4. 本地缓存cache

详情看文末链接

📌《Quarkus实战》链接: https://pan.baidu.com/s/1U3WVpIkFb_mjffTyF1zT2w?pwd=2p7r 提取码: 2p7r

posted @ 2022-12-22 12:11  老梁讲Java  阅读(500)  评论(0编辑  收藏  举报