《Quarkus实战》总结

news2024/11/17 1:43:54

《Quarkus实战》总结

目录

  • 一、优势
  • 二、搭建脚手架
  • 三、Rest
    • 1)启用跨源资源共享
    • 2)拦截HTTP请求
    • 3)使用SSL进行安全连接
  • 四、配置
    • 1)以程序化的方式访问配置属性
    • 2)在外部覆盖配置值
    • 3)修改日志配置
  • 五、编程模型
    • 1)校验输入值和输出值
    • 2)全局异常处理
    • 3)创建自定义校验
    • 4)以程序化的方式校验对象
    • 5)依赖注入
    • 6)创建工厂类
    • 7)如何在创建或销毁对象前后执行一些逻辑
    • 8)如何在应用程序启动或关闭后执行一些逻辑?
    • 9)如何用名字限定一个注解?
    • 10)如何使用注解来限定和配置依赖?
    • 11)创建拦截器
    • 12)测试端口
    • 13)单元测试
    • 14)使用Mockito创建mock对象
    • 15)元注解
    • 16)在测试代码前后执行代码
  • 六、打包Quarkus应用程序
  • 七、持久化
    • 1)配置数据源
    • 2)配置多数据源
    • 3)事务定义
    • 4)设置事务的上下文
    • 5)用Panache持久化数据
    • 6)更多Panache方法
    • 7)用Panache连接mongo
  • 八、容错
    • 1)自动重试
    • 2)超时
    • 3)过载保护
    • 4)断路器
    • 5)禁用容错
  • 九、可观察性
    • 1)健康检查
    • 2)自定义健康检查
    • 3)暴露服务指标
    • 4)创建指标
    • 5)分布式链路追踪
  • 十、认证和授权
    • 1)使用Elytron Security JDBC配置进行认证授权
  • 十一、使用Spring API开发Quarkus
    • 1)Spring依赖注入
    • 2)Spring Web
  • 十二、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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

荣耀加冕 大道可期 | WotoKOL卧兔荣获星球奖BrandStar Awards 2022服务创新奖

2022年11月&#xff0c;星球奖BrandStar Awards 2022获奖名单揭晓&#xff0c;WotoKOL卧兔荣获服务创新奖 &#xff01; 据了解&#xff0c;星球奖BrandStar Awards 是品牌星球于 2021 年发起的&#xff0c;以「品牌创新」为核心指标的奖项。星球奖系统囊括品牌建设的核心板块&…

【C语言】你知道程序是如何调用函数的吗?

目录 1.函数栈帧的含义 概念 要用到的汇编语言的知识 示例 2.理解栈帧 2.1 main函数栈帧的创建 2.2 局部变量的创建 2.3 函数传参 2.4 调用函数 2.5 函数返回 一个.c文件在调用函数的时候&#xff08;包括main 函数&#xff09;&#xff0c;其内存中的栈区有什么变…

祝贺誉天多位学员通过HCIE-Datacom,喜提誉天助跑奖学金

华为HCIE-Datacom自发布以来&#xff0c;就一直牵动着数通学员们的心。不论是版本之间的取舍&#xff0c;还是新增模块的学习&#xff0c;都一度引发热议。为了帮助各位小伙伴完成过渡顺利通过考试&#xff0c;誉天除了在师资、设备、教研等方面下足功夫之外&#xff0c;还专门…

12. 【gRPC系列学习】失败重试Retry原理

本节分析gRPC的失败重试机制,从原理、源码上进行深入分析,下节编写测试代码,验证Retry机制。 官方文档在失败重试方面的讲解比较透彻,下面内容是对官方文档的整理、归类、总结。 1. 两种重试策略简介 1)retry策略 retry策略:发送RPC,服务端应用层返回指定的异常码后,…

ES6--》了解并使用模块化规范

目录 ES6模块化规范 模块化的分类 ES6模块化的语法 ES6模块化规范 ES6模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学习成本&#xff0c;开发者不需要再额外的学习AMD、CMD或CommonJS等模块化规范。 ES6模块化规范定义&am…

激活海量数据价值,实现生产过程优化

背景 在全球掀起的新一轮工业转型浪潮中&#xff0c;智能制造面临巨大发展机遇。得益于云计算、大数据和人工智能技术的加持&#xff0c;工业转型升级进入新阶段&#xff0c;人们逐渐意识到由数据驱动催生的新商业模式所带来的巨大价值&#xff0c;数据和算法模型的结合与碰撞…

KMP算法,686. 重复叠加字符串匹配,

首先&#xff0c;要明白&#xff0c;如果b串的第一个字母b[0]在a串中没有找到&#xff0c;那么不管a串复制多少次&#xff0c;b串都不会是a的子串。 如果b串的第一个字母b[0]在a串中能找到&#xff0c;那么我们看一下a串需要复制几次呢&#xff1f; 总结,可以发现这四种情况是…

数据库系统概论第六章(关系数据理论)知识点总结(3)—— 范式知识点总结

本专栏收录了数据库的知识点&#xff0c;而从本文起&#xff0c;将讲述有关于关系数据理论中的第一范式、第二范式、第三范式以及BC范式有关知识点&#xff0c;提供给有需要的小伙伴进行学习&#xff0c;本专栏地址可以戳下面链接查看 &#x1f388; 数据库知识点总结&#xff…

windows CMD “ZEBAR ZPL 命令打印“驱动打印机

一、命令预览 copy WS20_8891898136BB520221221003.txt "\\10.165.98.33\IP-print-ZDesigner ZT411-203dpi ZPL" 二、难点打印机名称 1. copy 命令必须为共享打印机&#xff0c;及打印机共享名称&#xff0c;可以参考(163条消息) 发送ZPL指令到斑马打印机&#xff…

【Java对象拷贝机制】「实战开发专题」高性能使用CGlib实现Bean拷贝(BeanCopier)指南

对象拷贝现状 业务系统中经常需要两个对象进行属性的拷贝&#xff0c;不能否认逐个的对象拷贝是最快速最安全的做法&#xff0c;但是当数据对象的属性字段数量超过程序员的容忍的程度&#xff0c;代码因此变得臃肿不堪&#xff0c;使用一些方便的对象拷贝工具类将是很好的选择…

训练seq2seq模型的一些Tips——李宏毅机器学习笔记

Copy Mechanism 有时我们并不需要decoder创造一些东西出来&#xff0c;有些内容是可以从encoder复制而来。 最早具有复制能力的模型&#xff1a;Pointer Network 例如&#xff1a; chat-bot Summarization 至少要训练百万篇文章 Guided Attention Monotonic Attention Lo…

PPT怎么转化成PDF?这两种方法教你快速解决!

今天我们将向您介绍如何将 PowerPoint 演示文稿 (PPT) 转换为 PDF 文件。 我们将通过两种方法来做到这一点&#xff1a; 将 PowerPoint 演示文稿另存为 PDF 文件。使用 奇客免费PDF转换 将 PowerPoint 演示文稿转换为 PDF。方法一&#xff1a;使用 Microsoft PowerPoint 将 P…

合理利用chatGpt之新冠阳性

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;合理利用chatGpt之新冠阳性 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入:…

AI 预测到了正确的世界杯胜利者吗 ?

在过去的一个月里&#xff0c;卡塔尔 2022 年世界杯让我们目睹了一个又一个令人震惊的结果&#xff0c;甚至在决赛之前&#xff0c;让所有人的目光都聚焦在法国和阿根廷两支球队上&#xff0c;其实在球迷们心中&#xff0c;早就开始了各种猜测。&#x1f604;现在是时候回顾一下…

基于CNN和LSTM的气象图降水预测示例

我们是否可以通过气象图来预测降水量呢&#xff1f;今天我们来使用CNN和LSTM进行一个有趣的实验。 我们这里使用荷兰皇家气象研究所(也称为KNMI)提供的开放数据集和公共api&#xff0c;来获取数据集并且构建模型预测当地的降水量。 数据收集 KNMI提供的数据集&#xff0c;我…

excel函数公式大全,最常用的6个公式

Excel中的函数引用一些预定义的公式&#xff0c;可以通过输入参数值来计算函数的对应函数&#xff0c;并且函数名称基本上与函数相对应&#xff0c;这很容易记住。在日常工作中&#xff0c;功能可用于数据统计、计算、处理和分析。本文主要介绍EXCEL中一些常用公式&#xff0c;…

视唱练耳训练小程序开发,摆脱传统训练制约性

视唱练耳作为一门综合性的音乐基础理论学科&#xff0c;对于声乐、器乐、舞蹈等音乐学科中的各个方面都起着十分重要的作用&#xff0c;尤其是突出表现在基本理论、基本技能和音乐审美上&#xff0c;对培养和发展学生的乐感、唱奏技巧以及音乐思维等都有着非常重要的意义。世界…

Databend 开源周报 #71

Databend 是一款强大的云数仓。专为弹性和高效设计&#xff0c;自由且开源。 即刻体验云服务&#xff1a;https://app.databend.com。 What’s New 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 Features & Improvements Planner 优化集群模…

简单易用的监控告警系统 | HertzBeat 在 Rainbond 上的使用分享

在现有的监控告警体系中 Prometheus AlertManger Grafana 一直是主流&#xff0c;但对于中小团队或个人来说&#xff0c;这种体系显的较为复杂。而 HertzBeat 能让中小团队或个人很快速的搭建监控告警系统&#xff0c;并通过简单的配置实现应用、数据库、操作系统的监控与告警…

k8s HPA升级 KEDA 基于事件驱动的自动伸缩

说明&#xff1a;KEDA有啥用&#xff0c;相对HPA有啥优势。HPA针对于cpu,内存来进行弹性伸缩&#xff0c;有点不太精确。KEDA可以接入prometheus&#xff0c;根据prometheus的数据指标进行弹性伸缩&#xff0c;相比更加的精准实用。 安装k8s环境部署prometheus 创建ns&#xf…