调用代理方法

分析调用逻辑之前先上类图,看看Spring 中主要的AOP 组件:

上面我们已经了解到Spring 提供了两种方式来生成代理方式有JDKProxy 和CGLib。下面我们来研究一下Spring 如何使用JDK 来生成代理对象,具体的生成代码放在JdkDynamicAopProxy 这个类中,直接上相关代码:

/**
 * 获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy, Advised(opaque=false)
 * 检查上面得到的接口中有没有定义 equals或者hashcode的接口
 * 调用Proxy.newProxyInstance创建代理对象
 */
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
	}
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

通过注释我们应该已经看得非常明白代理对象的生成过程,此处不再赘述。下面的问题是,代理对象生成了,那切面是如何织入的?

我们知道InvocationHandler 是JDK 动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。而从JdkDynamicAopProxy 的源码我们可以看到这个类其实也实现了InvocationHandler,下面我们分析Spring AOP 是如何织入切面的,直接上源码看invoke()方法:

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

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

	try {
		//eqauls()方法,具目标对象未实现此方法
		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();
		}
		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.
		//获取可以应用到此方法上的Interceptor列表
		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.
		//如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
		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
			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);
		}
	}
}

主要实现思路可以简述为:首先获取应用到此方法上的通知链(Interceptor Chain)。如果有通知,则应用通知,并执行JoinPoint;如果没有通知,则直接反射执行JoinPoint。而这里的关键是通知链是如何获取的以及它又是如何执行的呢?现在来逐一分析。首先,从上面的代码可以看到,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现逻辑:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

通过上面的源码我们可以看到, 实际获取通知的实现逻辑其实是由AdvisorChainFactory 的getInterceptorsAndDynamicInterceptionAdvice()方法来完成的,且获取到的结果会被缓存。下面来分析getInterceptorsAndDynamicInterceptionAdvice()方法的实现:

/**
 * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor,
 * 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断
 * 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.
 */
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	//查看是否包含IntroductionAdvisor
	boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
	//这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

	for (Advisor advisor : config.getAdvisors()) {
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				//这个地方这两个方法的位置可以互换下
				//将Advisor转化成Interceptor
				MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
				//检查当前advisor的pointcut是否可以匹配当前方法
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
					if (mm.isRuntime()) {
						// Creating a new object instance in the getInterceptors() method
						// isn't a problem as we normally cache created chains.
						for (MethodInterceptor interceptor : interceptors) {
							interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
						}
					}
					else {
						interceptorList.addAll(Arrays.asList(interceptors));
					}
				}
			}
		}
		else if (advisor instanceof IntroductionAdvisor) {
			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

这个方法执行完成后,Advised 中配置能够应用到连接点(JoinPoint)或者目标类(Target Object)的Advisor 全部被转化成了MethodInterceptor,接下来我们再看下得到的拦截器链是怎么起作用的。

// 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.
//如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
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
	invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	// Proceed to the joinpoint through the interceptor chain.
	retVal = invocation.proceed();
}

从这段代码可以看出, 如果得到的拦截器链为空, 则直接反射调用目标方法, 否则创建MethodInvocation,调用其proceed()方法,触发拦截器链的执行,来看下具体代码:

@Override
@Nullable
public Object proceed() throws Throwable {
	//	We start with an index of -1 and increment early.
	//如果Interceptor执行完了,则执行joinPoint
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}

	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	//如果要动态匹配joinPoint
	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)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		//执行当前Intercetpor
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

至此,通知链就完美地形成了。我们再往下来看invokeJoinpointUsingReflection()方法,其实就是反射调用:

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);
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值