业务场景
拦截器的使用场景是比较多的,大致上有下面这些吧!
- 我就是想用拦截器:在某个业务中,开发人员觉得用拦截器是一种好的设计,那么就用起来。
- 我要自定义权限控制:可以通过拦截器实现登录验证、权限验证等安全控制。
- 我要自定义日志记录:可以通过拦截器记录请求和响应的日志信息,便于监控和分析系统运行状态。
- 我要自定义缓存处理:可以通过拦截器对请求进行缓存,提高系统的性能和响应速度。
- 我要自定义异常处理:可以通过拦截器捕获系统中的异常,进行处理和转换,提高系统的健壮性和容错性。
- 我要自定义数据处理:可以通过拦截器对请求和响应的数据进行处理和转换,以满足业务需求。
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,大致如下
大致原因是,在Quarkus Reactive中,线程是异步的,通过日志可以看到是vert.x的eventloop线程,这时候返回了一个Uni的对象,其实实际业务并没有执行。
总结
在Quarkus中,使用Reactive时,需要十分谨慎。特别很多开发文档,是针对同步模型的,对于Reactvie就需要额外的方式方法。
不过,Reactvie的效率十分高,您是否会选择使用Quarkus Reactive进行业务编码呢?