各种源码中的责任链模式浅析

一、 AOP中的责任链

AOP中的责任链是将所有元素封装到一个链条对象中记录,然后调用该链条对象的invoke方法,同时将链条传给链条节点,这样链条节点就可以控制链条是否继续往下走了。

  1. 首先看JdkDynamicAopProxy类中的invoke方法
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
	// We can skip creating a MethodInvocation: just invoke the target directly
	// Note that the final invoker must be an InvokerInterceptor so we know it does
	// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 获取拦截器链,执行拦截器的proceed方法。
else {
	// We need to create a method invocation...
	invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	// Proceed to the joinpoint through the interceptor chain.
	retVal = invocation.proceed();
}
  1. 然后到了ReflectiveMethodInvocation类中,这个类就是我们所谓的链条。
@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接口的对象,通过将链条(或者叫链条的控制权)交给对应的链条节点,这样在每个节点都可以控制链条是继续向下走,还是拦截等等。

二、Spring MVC中拦截器链

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中整个责任链的调用是有返回值的,而这里的责任链调用是没有返回值的,请求响应对象通过参数,作为上下文传入责任链的节点。

三、 Servlet中的Filter

Filter是作用在Servlet之前,可以对请求和响应进行预处理,与上面中的HandlerInterceptor不同。Filter是在到达Servlet就进行了过滤操作,Filter是Servlet规范中定义的,是Servlet容器支持的。拦截器在Spring容器内,由Spring进行管理,是Spring的组件,归Spring管理,配置在Spring文件中,因此可以使用Spring里的任何资源,对象等,Filter不行。

常见的方式是CompositeFilter,采用组合模式,对外暴露一个Filter,内部组合了一个Filter链表,然后挨个执行。这里的doFilter方法没有返回值,不会拦截请求,只会一个个往下传,比较简单。这种是做预处理的,而不是拦截请求。

四、Mybatis插件中的拦截器链

在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<Interceptor> interceptors = new ArrayList<Interceptor>();
    
  //遍历所有的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<Interceptor> 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<Class<?>, Set<Method>> 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<Method> 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方法完全由我们自己来决定。

五、 Netty中的ChannelPipeline

可以看到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;
}

六、 Tomcat中的Pipeline - Valve

这种Pipeline和Valve模式中,每个Valve可以感知到下一个Valve的位置,和五中的类似,类似一个链表的模式。 Valve有getNext方法和invoke方法。这样不管从哪个Valve开始执行都可以。通常由Pipeline来管理Valve之间的关系。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值