欢迎访问我的GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
本篇概览
- 本文是《quarkus依赖注入》系列的第五篇,经过前面的学习,咱们熟悉了依赖注入的基本特性,接下来进一步了解相关的高级特性,先从本篇的拦截器开始
- 如果您熟悉spring的话,对拦截器应该不会陌生,通过拦截器可以将各种附加功能与被拦截代码的主体解耦合,例如异常处理、日志、数据同步等多种场景
- 本篇会演示如何自定义拦截器,以及如何对bean的方法进行进行拦截,由以下章节构成
- 定义和使用拦截器的操作步骤介绍
- 拦截异常
- 拦截构造方法
- 获取被拦截方法的参数
- 多个拦截器之间传递参数
定义和使用拦截器的操作步骤介绍
- 定义和使用拦截器一共要做三件事:
- 定义:新增一个注解(假设名为A),要用@InterceptorBinding修饰该注解
- 实现:拦截器A到底要做什么事情,需要在一个类中实现,该类要用两个注解来修饰:A和Interceptor
- 使用:用A来修饰要拦截器的bean
- 整个流程如下图所示
- 接下来通过实战掌握拦截器的开发和使用,从最常见的拦截异常开始
拦截异常
-
写一个拦截器,在程序发生异常的时候可以捕获到并将异常打印出来
-
首先是定义一个拦截器,这里的拦截器名为HandleError,注意要用InterceptorBinding修饰
package com.bolingcavalry.interceptor.define;
import javax.interceptor.InterceptorBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
@InterceptorBinding
@Target({TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandleError {
}
- 其次是实现拦截器的具体功能,下面代码有几处要注意的地方稍后会提到
package com.bolingcavalry.interceptor.impl;
import com.bolingcavalry.interceptor.define.HandleError;
import io.quarkus.arc.Priority;
import io.quarkus.logging.Log;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
@HandleError
@Interceptor
@Priority(Interceptor.Priority.APPLICATION +1)
public class HandleErrorInterceptor {
@AroundInvoke
Object execute(InvocationContext context) {
try {
// 注意proceed方法的含义:调用下一个拦截器,直到最后一个才会执行被拦截的方法
return context.proceed();
} catch (Exception exception) {
Log.errorf(exception,
"method error from %s.%s\n",
context.getTarget().getClass().getSimpleName(),
context.getMethod().getName());
}
return null;
}
}
- 上述代码有以下四点需要注意:
- Priority注解的作用是设定HandleError拦截器的优先级(值越小优先级越高),可以同时用多个拦截器拦截同一个方法
- AroundInvoke注解的作用,是表明execute会在拦截bean方法时被调用
- proceed方法的作用,并非是执行被拦截的方法,而是执行下一个拦截器,直到最后一个拦截器才会执行被拦截的方法
- 可以从入参context处取得被拦截实例和方法的信息
- 然后是使用拦截器,这里创建个bean来演示拦截器如何使用,bean里面有个业务方法会抛出异常,可见拦截器使用起来很简单:用HandleError修饰bean即可
@ApplicationScoped
@HandleError
public class HandleErrorDemo {
public void executeThrowError() {
throw new IllegalArgumentException("this is business logic exception");
}
}
- 验证拦截器的单元测试代码如下,只要执行HandleErrorDemo的executeThrowError方法就会抛出异常,然后观察日志中是否有拦截器日志信息即可验证拦截器是否符合预期
@QuarkusTest
public class InterceptorTest {
@Inject
HandleErrorDemo handleErrorDemo;
@Test
public void testHandleError() {
handleErrorDemo.executeThrowError();
}
}
- 执行单元测试,如下图红框所示,拦截器捕获了异常并打印出异常信息
- 至此,拦截异常的操作就完成了,除了用AroundInvoke拦截普通的bean方法,还能用AroundConstruct拦截bean的构造方法,接下里编码体验
拦截构造方法
- 拦截器定义
@InterceptorBinding
@Target({TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandleConstruction {
}
- HandleConstruction拦截器的实现,要注意的有两点稍后会提到
@HandleConstruction
@Interceptor
@Priority(Interceptor.Priority.APPLICATION +1)
public class HandleConstructionInterceptor {
@AroundConstruct
void execute(InvocationContext context) throws Exception {
// 执行业务逻辑可以在此