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 BeginAudit SucceededLogging End
小结
拦截器模式在开源框架中被广泛使用,例如,MVC框架Struts2的Interceptor机制正是使用该模式,只是在Struts2中Target叫Action,TargetInvocation叫ActionInvocation。在开源流程引擎Activity中也有使用该模式,其Target叫Command。在COLA框架中,同样使用拦截器模式来进行Command的前置和后置处理。