1 定义
拦截器模式(Interceptor Pattern),是指提供一种通用的扩展机制,可以在业务操作前后提供一些切面的(Cross-Cutting)的操作。这些切面操作通常是和业务无关的,比如日志记录、性能统计、安全控制、事务处理、异常处理和编码转换等。
在功能上,拦截器模式和面向切面编程(Aspect OrientedProgramming,AOP)的思想很相似。
推荐拦截器的实现方式的原因:
- 一个其命名更能表达前置处理和后置处理的含义。
- 拦截器的添加和删除会更加灵活。
2 设计原理
不同于Java的动态代理是利用Java反射机制的,拦截器模式完全是利用面向对象技术的,巧妙地使用组合模式外加递归调用实现了灵活、可扩展的前置处理和后置处理。
在拦截器模式中,主要包含以下角色:
- TargetInvocation:包含了一组Interceptor和一个Target对象,确保在Target处理请求前后,按照定义顺序调用Interceptor做前置和后置处理。
- Target:处理请求的目标接口。
- Interceptor:拦截器接口。
- InterceptorImpl:拦截器实现,用来在Target处理请求前后做切面处理。
各角色之间的关系如下类图所示:
编码实现
创建Target接口
public interface Target{
public Response execute(Request request);
}
创建Interceptor接口
public interface Interceptor {
public Response intercept(TargetInvocation targetInvocation);
}
创建TargetInvocation
public class TargetInvocation {
private List<Interceptor> interceptorList = new ArrayList<>();
private Iterator<Interceptor> interceptors;
private Target target; private Request request;
public Response invoke(){
if( interceptors.hasNext() ){
//此处是整个算法的关键,这里会递归调用invoke()
Interceptor interceptor = interceptors.next();
interceptor.intercept(this);
}
return target.execute(request);
}
public void addInterceptor(Interceptor interceptor){
//添加新的Interceptor到TargetInvocation中
interceptorList.add(interceptor);
interceptors = interceptorList.iterator();
}
}
创建具体的Interceptor
AuditInterceptor实现如下:
public class AuditInterceptor implements Interceptor{
@Override
public Response intercept(TargetInvocation targetInvocation) {
if(targetInvocation.getTarget() == null) {
throw new IllegalArgumentException("Target is null");
}
System.out.println("Audit Succeeded ");
return targetInvocation.invoke();
}
}
LogInterceptor实现如下:
public class LogInterceptor implements Interceptor {
@Override
public Response intercept(TargetInvocation targetInvocation) {
System.out.println("Logging Begin");
Response response = targetInvocation.invoke();
System.out.println("Logging End");
return response;
}
}
InterceptorDemo演示
public class InterceptorDemo {
public static void main(String[] args) {
TargetInvocation targetInvocation = new TargetInvocation();
targetInvocation.addInterceptor(new LogInterceptor());
targetInvocation.addInterceptor(new AuditInterceptor());
targetInvocation.setRequest(new Request());
targetInvocation.setTarget(request->{return new Response();});
targetInvocation.invoke();
}
}
输出结果
Logging Begin
Audit Succeeded
Logging End
小结
拦截器模式在开源框架中被广泛使用,例如,MVC框架Struts2的Interceptor机制正是使用该模式,只是在Struts2中Target叫Action,TargetInvocation叫ActionInvocation。在开源流程引擎Activity中也有使用该模式,其Target叫Command。在COLA框架中,同样使用拦截器模式来进行Command的前置和后置处理。