拦截器模式,顾名思义,对请求进行拦截,既可以请求执行前拦截,也可以在请求处理之后拦截。在请求到达实际请求目标之前,进行拦截,对请求进行预处理,比如认证、鉴权、记录日志。拦截也可以后置处理,可以记录日志信息,计算请求调用时间等。
拦截器模式的实践
springMVC请求拦截过程就是一个经典的拦截器模式实践,通过对http请求在拦截器链中进行匹配,筛选出匹配成功的拦截器列表,遍历列表,进行请求拦截操作,进行预处理或后置处理。
那如何设计一个简单的拦截器实践?
参考SpringMVC源码,设计一个简单的拦截器实践。
- 定义拦截器
- 拦截器管理
- 发起请求
1.定义拦截器,首先定义一个拦截器接口,接口是行为的规范,即拥有什么功能
/**
* @author yujiaxing
* @date 2021/09/27
*/
public interface Interceptor{
// 前置拦截
void before(InvocationChain invocationChain);
// 拦截
void intercept(InvocationChain invocationChain, String param);
// 后置拦截
void after(InvocationChain invocationChain);
}
#定义多个拦截器,这里定义两个拦截器 LogInterceptor,SensitiveInfoConversionInterceptor
# LogInterceptor定义
/**
* @author yujiaxing
* @date 2021/09/27
*/
@Component
public class LogInterceptor implements Interceptor {
@Resource
private BusinessService businessService;
@Override
public void before(InvocationChain invocationChain) {
System.out.println("LogInterceptor before ...");
}
@Override
public String intercept(InvocationChain invocationChain, String param) {
this.before(invocationChain);
businessService.logRecord(param);
invocationChain.invoke(param);
this.after(invocationChain);
return null;
}
@Override
public void after(InvocationChain invocationChain) {
System.out.println("LogInterceptor after ...");
}
}
# SensitiveInfoConversionInterceptor 定义
/**
* @author yujiaxing
* @date 2021/09/27
*/
@Component
public class SensitiveInfoConversionInterceptor implements Interceptor {
@Resource
private BusinessService businessService;
@Override
public void before(InvocationChain invocationChain) {
System.out.println("SensitiveInfoConversionInterceptor before ...");
}
@Override
public void intercept(InvocationChain invocationChain, String param) {
this.before(invocationChain);
businessService.sensitiveInfoConversion(param);
invocationChain.invoke(param);
this.after(invocationChain);
}
@Override
public void after(InvocationChain invocationChain) {
System.out.println("SensitiveInfoConversionInterceptor after ...");
}
}
# 其中业务类的定义
/**
* @author yujiaxing
* @date 2021/09/27
*/
@Service
public class BusinessService {
public void perform(String param) {
System.out.println("【正常请求----业务代码】,当前参数:"+param);
}
public void logRecord(String param) {
System.out.println("【日志拦截业务代码】,当前参数:"+param);
}
public void sensitiveInfoConversion(String param) {
System.out.println("【敏感信息转换业务代码】转换前参数:"+param+" , 转换后参数:"+param.replace("大大大","**"));
}
}
2.定义拦截器链
/**
* @author yujiaxing
* @date 2021/09/27
*/
@Data
public class InvocationChain {
private int index = 0;
private List<Interceptor> interceptorList;
private BusinessService businessService = new BusinessService();
public void invoke(String request) {
if (index != interceptorList.size()) {
Interceptor interceptor = interceptorList.get(index);
index++;
interceptor.intercept(this, request);
}else{
businessService.perform(request);
}
}
}
3.测试,发起请求
@SpringBootTest
class InvocationChainTest {
@Autowired
BusinessService businessService;
@Autowired
private LogInterceptor logInterceptor;
@Autowired
private SensitiveInfoConversionInterceptor sensitiveInfoConversionInterceptor;
@Test
public void testInterceptor() {
// 定义过滤器链,添加过滤器
InvocationChain invocationChain = new InvocationChain();
ArrayList<Interceptor> interceptors = new ArrayList<>();
interceptors.add(logInterceptor);
interceptors.add(sensitiveInfoConversionInterceptor);
invocationChain.setInterceptorList(interceptors);
// 发起请求
String param = "金箍棒,大大大大";
invocationChain.invoke(param);
}
}
结果如下:
拦截器是函数递归调用,处理流程和栈一样,先进后出。