e com.bolingcavalry.interceptor.impl;
import com.bolingcavalry.interceptor.define.SendMessage;
import com.bolingcavalry.interceptor.define.TrackParams;
import io.quarkus.arc.Priority;
import io.quarkus.arc.runtime.InterceptorBindings;
import io.quarkus.logging.Log;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import java.lang.annotation.Annotation;
import java.util.*;
import static io.quarkus.arc.ArcInvocationContext.KEY_INTERCEPTOR_BINDINGS;
@SendMessage
@Interceptor
public class SendMessageInterceptor {
@AroundInvoke
Object execute(InvocationContext context) throws Exception {
// 先执行被拦截的方法
Object rlt = context.proceed();
// 获取被拦截方法的类名
String interceptedClass = context.getTarget().getClass().getSimpleName();
// 代码能走到这里,表示被拦截的方法已执行成功,未出现异常
// 从context中获取通知类型,由于允许重复注解,因此通知类型可能有多个
List<String> allTypes = getAllTypes(context);
// 将所有消息类型打印出来
Log.infov("{0} messageTypes : {1}", interceptedClass, allTypes);
// 遍历所有消息类型,调用对应的方法处理
for (String type : allTypes) {
switch (type) {
// 短信
case "sms":
sendSms();
break;
// 邮件
case "email":
sendEmail();
break;
}
}
// 最后再返回方法执行结果
return rlt;
}
/**
* 从InvocationContext中取出所有注解,过滤出SendMessage类型的,将它们的type属性放入List中返回
* @param invocationContext
* @return
*/
private List<String> getAllTypes(InvocationContext invocationContext) {
// 取出所有注解
Set<Annotation> bindings = InterceptorBindings.getInterceptorBindings(invocationContext);
List<String> allTypes = new ArrayList<>();
// 遍历所有注解,过滤出SendMessage类型的
for (Annotation binding : bindings) {
if (binding instanceof SendMessage) {
allTypes.add(((SendMessage) binding).sendType());
}
}
return allTypes;
}
/**
* 模拟发送短信
*/
private void sendSms() {
Log.info("operating success, from sms");
}
/**
* 模拟发送邮件
*/
private void sendEmail() {
Log.info("operating success, from email");
}
}
- 发送短信和邮件不是本篇的重点,因此,对应的sendSms和sendEmail方法中只是日志打印,表示代码已经走到了此处
- getAllTypes方法是重点,演示了如何从拦截器上下文对象invocationContext中获取所有注解,并过滤出所有SendMessage类型,再取其type属性
- 对取出的sendType属性逐一处理,这样就做到了每个设置的类型都会被处理
- 在某个方法上多次用SendMessage注解修饰,最终只会执行一次SendMessageInterceptor#execute方法,这是关键!试想,如果SendMessageInterceptor#execute方法执行了多次,而每次都会取出所有SendMessage类型去处理,那么每种SendMessage类型都会重复处理
编码:使用拦截器
- 拦截器的定义和实现都已经完成,接下来就是使用拦截器了,注意前面提到的限制,这里要用SendMessage去修饰方法,而不能修饰类
- 首先是SayHelloA,拦截它的时候,业务需求是发送短信,修改后的完整源码如下,用SendMessage注解修饰hello方法,这里的SendMessage没有指定其sendType的值,因此会使用默认值sms
@ApplicationScoped
@Named("A")
public class SayHelloA implements SayHello {
@SendMessage
@Override
public void hello() {
Log.info("hello from A");
}
}
- 然后是SayHelloB,拦截它的时候,业务需求是发送邮件,注意sendType值等于email
@ApplicationScoped
@Named("B")
public class SayHelloB implements SayHello {
@SendMessage(sendType = "email")
@Override
public void hello() {
Log.info("hello from B");
}
}
- 最后是SayHelloC,拦截它的时候,也无需求是短信和邮件都要发送,注意这里使用了两次SendMessage
@ApplicationScoped
@Named("C")
public class SayHelloC implements SayHello {
@SendMessage
@SendMessage(sendType = "email")
@Ove