AOP中的责任链是将所有元素封装到一个链条对象中记录,然后调用该链条对象的invoke方法,同时将链条传给链条节点,这样链条节点就可以控制链条是否继续往下走了。
// Get the interception chain for this method.
List
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
// 将自己传到链条的节点中,这里执行的是对应的Advice
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
通过下标索引来记录了当前执行的链条节点,将this传递到相应的节点。下面我们看一下对应节点的实现:
Advice有很多种,我们这里介绍@AfterReturning对应的Advice,它们都实现了MethodInterceptor方法。
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 让链条向下执行
Object retVal = mi.proceed();
// 执行完后再执行拦截方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
综上所述,Spring中AOP的责任链方式采用的是链条 + 节点的方式。ReflectiveMethodInvocation是链条,其中的节点是实现了MethodInterceptor接口的对象,通过将链条(或者叫链条的控制权)交给对应的链条节点,这样在每个节点都可以控制链条是继续向下走,还是拦截等等。
SpringMvc中将请求映射到对应的Handler时,采用了责任链的方式对请求进行了拦截处理。 具体方式是在AbstractHandlerMapping类中的gethandler方法中返回了一个处理器链HandlerExecutionChain。
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
然后HandlerExecutionChain中包含了许多个HandlerInterceptor + 一个handler,然后通过调用applyPrehandle方法来触发责任链。
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
小结:
这里的用法依旧是通过下标来修改当前正在运行的节点的位置,并且通过返回true或者false来决定是否继续向下执行。这里就没有像AOP那种把链条传入节点的方式。 由于AOP中整个责任链的调用是有返回值的,而这里的责任链调用是没有返回值的,请求响应对象通过参数,作为上下文传入责任链的节点。
Filter是作用在Servlet之前,可以对请求和响应进行预处理,与上面中的HandlerInterceptor不同。Filter是在到达Servlet就进行了过滤操作,Filter是Servlet规范中定义的,是Servlet容器支持的。拦截器在Spring容器内,由Spring进行管理,是Spring的组件,归Spring管理,配置在Spring文件中,因此可以使用Spring里的任何资源,对象等,Filter不行。
常见的方式是CompositeFilter,采用组合模式,对外暴露一个Filter,内部组合了一个Filter链表,然后挨个执行。这里的doFilter方法没有返回值,不会拦截请求,只会一个个往下传,比较简单。这种是做预处理的,而不是拦截请求。
在org.apache.ibatis.session包中有一个类Configuration,它的一个方法newExecutor用来生成Exetucor时,使用了InterceptorChain属性,InterceptorChain中记录了所有注入的拦截器Interceptor。它用于生成代理的Executor。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 使用拦截器链来生成代理executor
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
上面代码可以看到, executor = (Executor) interceptorChain.pluginAll(executor);这行代码,拦截器链生成了一个代理的executor,然后看下InterceptorChain的实现,很简单:
public class InterceptorChain {
private final List interceptors = new ArrayList();
//遍历所有的Interceptor,分别指向plugin,生成代理对象。
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
这里和前面的责任链略有不同,这里使用代理的方式,通过层层代理的方式来实现功能的扩展。
public interface Interceptor {
// 当代理对象执行时会调用这个方法
Object intercept(Invocation invocation) throws Throwable;
// 入参是执行对象,出参是被代理后的对象。
Object plugin(Object target);
void setProperties(Properties properties);
}
常见的方式是使用静态方法Plugin.wrap来创建一个JDK动态代理:
public static Object wrap(Object target, Interceptor interceptor) {
Map, Set> signatureMap = getSignatureMap(interceptor);
Class type = target.getClass();
Class[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 生成代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
// 当代理对象方法被执行时,会回去执行拦截器的intercept方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
mybatis插件的拦截器链相对前面两种较为复杂一些,它是通过将链条上的每个拦截器作为一层层的代理生成器,来起到拦截和增强的功能。这样的方式扩展性更强,最终返回什么样的代理对象,以及如何触发拦截器的intercept方法完全由我们自己来决定。
可以看到ChannelPipeline自身定义了很多类似链表的add,addFirst,remove等操作,默认实现DefaultChannelPipeline中构造函数可以看出这是一个双向链表。这个链条自身支持新增和移除操作,每个节点是一个处理器。
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
这种Pipeline和Valve模式中,每个Valve可以感知到下一个Valve的位置,和五中的类似,类似一个链表的模式。 Valve有getNext方法和invoke方法。这样不管从哪个Valve开始执行都可以。通常由Pipeline来管理Valve之间的关系。