Spring AOP源码分析七

上一篇中,我们通过JDK动态代理已经生成了代理对象,AOP通过JDK创建的动态代理对象,最终都会执行JdkDynamicAopProxy类的invoke()方法,而在这个invoke()方法中,就会来执行目标方法和切面中的增强逻辑了,那执行过程到底是怎么样的呢?我们今天就来分析下这个invoke()方法:

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 {
			// 对equals 方法的处理
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			// 对hashCode方法的处理
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			// 对DecorationgProxy接口中定义方法的处理
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			// 如果是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;

			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.
			// 获取当前调用方法的拦截器链, advised就是一个ProxyFactory
			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);
			}
			else {
				// We need to create a method invocation...
				// 如果拦截链不为空,则将拦截器统一封装为MethodInvocation
				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()方法时需要执行的代码,我们看到有很多的if 判断,那这些if判断是做什么呢?我们看到前两个if分支的条件,分别调用了isEqualsMethod()和isHashCodeMethod()方法完成了判断,我们直接点进去看下这两个方法的代码,如下图:
在这里插入图片描述通过上边的代码,我们可以看到,这两个方法上分别有一段注释,大概意思就是说,判断给定的这个方法是不是equals方法和hashCode方法。也就是说如果当前调用的是equals方法的话,那么就执行equals(args[0])这行代码完成处理,而如果是hashCode方法的话,则执行hashCode()这行代码进行处理,而调用的equals(args[0])和hashCode()其实就是JdkDynamicAopProxy类中定义的两个方法而已,代码如下:
在这里插入图片描述
在这里插入图片描述
可以看到,我们现在不知道这块代码为什么要这样处理?首先我们都知道在调用代理对象的方法时,在invoke()方法中会为我们调用的目标方法添加增强,如果调用的这个方法是我们接口中定义的方法,比如ProductService接口中定义的addProduct()方法和getProductById()方法,如下代码:

// 接口
public interface ProductService {

void addProduct(Product product);

Product getProductById(Integer productId);
}

// 实现类
public class ProductServiceImpl implements ProductService  {

public void addProduct(Product product){
}

public Product getProductById(Integer productId){
 
 }
}

也就是说当调用代理对象中的addProduct()方法和getProductById()方法时,invoke()方法就会执行我们的增强逻辑。如果调用的是代理对象的equals方法和hashCode方法,还有没有必要为这两个方法添加逻辑呢?我们知道这两个方法是Object类中定义的方法!如果代理接口ProductService中声明了equals方法和hashCode方法,且目标类productServiceImpl中重写了这两个方法,此时就会为equals方法和hashCode方法执行增强逻辑,否则将直接调用JdkDynamicAopProxy类中定义的equals方法和hashCode方法来完成处理。那么怎么判断代理接口中有没有声明equals方法和hashCode方法呢?其实通过这两个变量就可以,如下图:
在这里插入图片描述
我们看下边这块代码:
在这里插入图片描述其实就是当代理接口中没有定义equals方法和hashCode方法时,就直接使用JdkDynamicAopProxy类中的equals方法和hashCode方法完成判断,否则就正常为equals方法和hashCode方法添加增强逻辑。
我们在看下这个代码是做什么的:
在这里插入图片描述
这块代码首先通过getDeclaringClass()方法获取到当前方法的声明类,然后再使用获取到的声明类判断这个类是不是指定类,说白了一个是对DecoratingProxy接口中定义方法的处理,一个是对Advised类型的接口中定义的方法的处理,其实我们刚才分析的这一大块代码,都只是在刚进入invoke()方法时,对特定方法和特定类的单独处理,接下来才是真正的处理,也就是执行切面中定义的增强逻辑。
我们接着下边这块代码看下:
在这里插入图片描述
我们可以看到其中使用了一个叫做targetSource的属性,那这个targetSource是什么呢?其实这个targetSource在前边已经定义了,targetSource定义的代码如下:
在这里插入图片描述
我们可以看到,这里直接将this.advised.targetSource赋值给了targetSource,那么这个advised又是什么呢?我们来看下advised的定义就知道了,我们看这里:
在这里插入图片描述
在这里插入图片描述
通过上边的代码,我们可以看到,advised是JdkDynamicAopProxy类中的一个变量,并且是在构造方法中完成的初始化。那是因为之前我们分析过这个构造方法,我们看下边的代码:
在这里插入图片描述
通过上边的代码,我们可以看到,其实就是在创建jdk代理时,将入参config赋值给了advised变量,那么这个入参config到底是谁呢?这个config就是之前我们分析过的ProxyFactory,我们看下边的代码:
在这里插入图片描述
上边代码中的ProxyFactory,之前我们分析过的,这个ProxyFactory就是创建代理最重要的配置,可以看到,这里为ProxyFactory设置了很多关键的属性,比如将增强advisors和目标类targetSource设置到ProxyFactory中。
说白了JdkDynamicAopProxy中的advised属性其实就是之前我们分析过的ProxyFactory,这个ProxyFactory中包含了增强advisors和目标类targetSource等核心属性。我们继续往下分析invoke()方法,我们看下边这块代码:
在这里插入图片描述
通过上边的代码,大家可以看到,这里会先从advised中获取到targetSource,说白了就是从ProxyFactory中获取到当时设置的目标对象targetSource,然后再进一步获取到目标对象的class对象并赋值给targetClass。接着就会调用advised(也就是ProxyFactory)中的getInterceptorsAndDynamicInterceptionAdvice()方法,并将目标类(ProductServiceImpl)和当前要执行的方法method作为入参传递进去,最后就可以获取到当前方法method要执行的拦截器链chain了,可以看到,这个chain就是一个List集合。那么这个getInterceptorsAndDynamicInterceptionAdvice()方法具体是怎么处理的呢?我们大概想一下就知道了,在advised(也就是ProxyFactory)中是有所有增强advisors的,是通过addAdvisors()方法将增强advisors设置给了ProxyFactory,所以getInterceptorsAndDynamicInterceptionAdvice()方法肯定是根据advisors经过处理获取到了最终的拦截器链。我们继续往下看,接着我们会看到这样一块代码:
在这里插入图片描述
其实这里就是会看一下拦截器链chain是不是为空?如果拦截器链chain为空的话,那么就直接执行目标方法,其中invokeJoinpointUsingReflection()方法的定义如下:
在这里插入图片描述
可以看到,这个核心代码就是method.invoke(target, args)这一代码,说白了就是通过反射执行目标方法。而如果拦截器链chain不为空的话,就会执行下边这块代码:
在这里插入图片描述
这里会先将拦截器链统一封装为MethodInvocation,然后再执行retVal = invocation.proceed()这行代码,其实就是真正去执行拦截器链。我们继续往下看,我们知道有的方法是有出参的,比如我们的接口getProductById()方法会返回一个商品Product,那么当拦截器链执行完毕后,该怎么返回出参呢?此时我们会看到这块代码:
在这里插入图片描述
大家可以看到,其实就是根据returnType对返回值retVal做了简单的处理。这个返回类型returnType很简单,如果你这个方法不需要返回出参,此时returnType的值就是void类型,而如果你这个方法需要返回一个商品Product,此时returnType的值就是com.younger.aop.model.Product类型,最后将返回值retVal直接return回去。

一张图来梳理下AOP代理的执行流程:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

youngerone123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值