Spring AOP拦截器调用的实现

前置博文:
Spring AOP中如何为Bean创建代理?
Spring AOP中是如何注册Advisor的?
Spring AOP如何为目标方法创建拦截器链?
Spring AOP拦截器调用的实现
Spring AOP中CGLIB代理对象增强通知执行原理

在Spring AOP通过jdk的proxy方式或者CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。

如果使用jdk的proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调。而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,提供过DynamicAdvisedInterceptor来完成回调。

【1】JdkDynamicAopProxy的invoke拦截

JdkDynamicAopProxy 实现了AopProxy, InvocationHandler, Serializable接口,内部维护了AdvisedSupport advised成员。

那么也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截或者说功能增强的工作。

其invoke方法如下所示,对Proxy对象的代理设置是在invoke方法中完成的,这些设置包括获取目标对象、拦截器链,同时把这些对象作为输入创建了ReflectiveMethodInvocation对象,通过这个对象来完成对AOP功能实现的封装。

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;

	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
		// 如果目标对象没有实际object类的基本方法:equals
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			return equals(args[0]);
		}
		// 如果目标对象没有实际object类的基本方法:hashCode
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			return hashCode();
		}
		
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		//根据代理对象的配置来调用服务
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		Object retVal;

		//将代理对象暴露给AopContext
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		// 得到目标对象的地方
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 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.
			// 如果没有设定拦截器则直接调用target的对应方法
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
		// 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
		// 通过构造一个ReflectiveMethodInvocation赖世雄
			// We need to create a method invocation...
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			// 沿着拦截器链继续前进
			retVal = invocation.proceed();
		}

		// Massage return value if necessary.
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

在这个invoke方法中,包含了一个完成的拦截器链对目标对象的拦截过程,比如获得拦截器链并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强,直到最后对目标对象方法的运行等。

【2】CglibAopProxy的intercept拦截

在分析CglibAopProxy的代理对象生成的时候,我们了解到对于AOP的拦截调用其回调是在DynamicAdvisedInterceptor对象中实现的,这个回调的实现在intercept方法中。

CglibAopProxy的intercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常类似的,只是在DynamicAdvisedInterceptor的intercept方法中构造的是CglibMethodInvocation对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过构造ReflectiveMethodInvocation对象来完成这个功能的。

需要注意点的是,CglibMethodInvocation是CglibAopProxy的静态内部类,继承于ReflectiveMethodInvocation重写了proceed方法。

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	TargetSource targetSource = this.advised.getTargetSource();
	try {
		// 暴露proxy给AopContext
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
		// 获取target
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		// 核心方法,获取拦截器链
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// Check whether we only have one InvokerInterceptor: that is,
		// no real advice, but just reflective invocation of the target.
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
			// 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);
			// 这里通过methodProxy实现
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			// We need to create a method invocation...
			// 封装CglibMethodInvocation 调用proceed,执行拦截器链
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

【3】目标对象方法的调用

如果没有设置拦截器,那么会对目标对象的方法直接进行调用。对于JdkDynamicAopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在 AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse)的方法中实现的。

代码如下所示,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。

public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
		throws Throwable {

	// Use reflection to invoke the method.
	try {
	// 设置访问权限
		ReflectionUtils.makeAccessible(method);
		// 方法反射调用
		return method.invoke(target, args);
	}
	catch (InvocationTargetException ex) {
		// Invoked method threw a checked exception.
		// We must rethrow it. The client won't see the interceptor.
		throw ex.getTargetException();
	}
	catch (IllegalArgumentException ex) {
		throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
				method + "] on target [" + target + "]", ex);
	}
	catch (IllegalAccessException ex) {
		throw new AopInvocationException("Could not access method [" + method + "]", ex);
	}
}

对于使用CglibAopProxy代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,这个对象的使用是由CGLIB的设计决定的。具体的调用在DynamicAdvisedInterceptor的intercept方法可以看到,使用的是CGLIB封装好的功能。相对JdkDynamicAopProxy的实现来说,形式上看起来较为简单,但它们的功能却是一样的,都是完成对目标对象方法的调用。

retVal = methodProxy.invoke(target, argsToUse);
// org.springframework.cglib.proxy.MethodProxy#invoke
public Object invoke(Object obj, Object[] args) throws Throwable {
	try {
		init();
		FastClassInfo fci = fastClassInfo;
		return fci.f1.invoke(fci.i1, obj, args);
	}
	catch (InvocationTargetException ex) {
		throw ex.getTargetException();
	}
	catch (IllegalArgumentException ex) {
		if (fastClassInfo.i1 < 0)
			throw new IllegalArgumentException("Protected method: " + sig1);
		throw ex;
	}
}

【4】AOP拦截器链的调用

AOP对目标对象增强是通过将实现封装在AOP拦截器链中,由一个个具体的拦截器完成的。对于jdk和CGLIB两种方式来言,虽然使用了不同的AopProxy代理对象,但最终对AOP拦截的处理可谓殊途同归:它们对拦截器链的调用都是在ReflectiveMethodInvocation的proceed方法实现的。在proceed方法中,会逐个运行拦截器的拦截方法。

在运行拦截器的拦截方法之前,需要对代理方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。即我们熟知的Pointcut切点中需要进行matches的匹配过程,即matches调用对方法进行匹配判断,来决定是否需要实行通知增强。

如下代码所示,在proceed方法中,先进行判断如果现在已经运行到拦截器链的末尾,俺么就会直接调用目标对象的实现方法。否则,沿着拦截器链继续进行,得到下一个拦截器。通过这个拦截器进行matches判断,判断是否适用于横切增强的场合。如果是,从拦截器得到通知器,并启动通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed凡那个发,直到拦截器链当中的拦截器都完成以上的拦截过程为止。

public Object proceed() throws Throwable {
	// We start with an index of -1 and increment early.
	// 从索引为-1的拦截器开始调用,并按序递增;
	//如果拦截器链中拦截器均执行完,这里调用目标对象的方法
	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;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			// 如果不匹配则递归调用proceed
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		// 如果是一个Interceptor,直接调用这个Interceptor对应的方法
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值