✅Quarkus中拦截器的使用

361 阅读2分钟

业务场景

拦截器的使用场景是比较多的,大致上有下面这些吧!

  • 我就是想用拦截器:在某个业务中,开发人员觉得用拦截器是一种好的设计,那么就用起来。
  • 我要自定义权限控制:可以通过拦截器实现登录验证、权限验证等安全控制。
  • 我要自定义日志记录:可以通过拦截器记录请求和响应的日志信息,便于监控和分析系统运行状态。
  • 我要自定义缓存处理:可以通过拦截器对请求进行缓存,提高系统的性能和响应速度。
  • 我要自定义异常处理:可以通过拦截器捕获系统中的异常,进行处理和转换,提高系统的健壮性和容错性。
  • 我要自定义数据处理:可以通过拦截器对请求和响应的数据进行处理和转换,以满足业务需求。

Quarkus

刚开始使用Quarkus时,可能使用起来不是那么容易,这里说一下Quarkus中关于拦截器的使用。

定义注解

在我们的设计中,使用此注解标识的方法,才会被拦截器拦截!

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.interceptor.InterceptorBinding;

@InterceptorBinding 
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) 
@Inherited 
public @interface MyInterceptorMethod {
    // ...
}

其中 @InterceptorBinding 不要丢掉哈。

定义拦截器

在我们的设计中,针对 被@MyInterceptorMethod 注解的方法,需要进行额外的业务处理。

import jakarta.annotation.Priority;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;

@MyInterceptorMethod 
@Priority(2023) 
@Interceptor
public class LoggingInterceptor {

   @Inject 
   Logger logger;

   @AroundInvoke 
   Object logInvocation(InvocationContext context) {
      // 在执行方法前,我们可以做些事情
      Object ret = context.proceed(); 
      // 在执行方法后,我们可以做些事情
      return ret;
   }

}

其中 @Priority 设置了拦截器的优先级。

在Reactive下的拦截器

当我们使用的是Quarkus Reactive时,拦截器的处理会出现问题。

   @AroundInvoke 
   Object logInvocation(InvocationContext context) {
      // 在执行方法前,我们可以做些事情
      Object ret = context.proceed(); 
      // 在执行方法后,我们可以做些事情
      return ret;
   }

这段代码参考了一个Issue,大致如下

image.png

大致原因是,在Quarkus Reactive中,线程是异步的,通过日志可以看到是vert.x的eventloop线程,这时候返回了一个Uni的对象,其实实际业务并没有执行。

image.png

总结

在Quarkus中,使用Reactive时,需要十分谨慎。特别很多开发文档,是针对同步模型的,对于Reactvie就需要额外的方式方法。

不过,Reactvie的效率十分高,您是否会选择使用Quarkus Reactive进行业务编码呢?