Spring AOP原理之代理组件执行目标方法

目录

1. 说明

2. 目标方法执行

3. 总结

1. 说明

在IOC容器中获取目标组件的时候,实际获取到的是增强后的代理组件,执行目标方法的时候,也是由此代理组件去执行;

public static void main(String[] args) throws Exception {
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigForAop.class);

	//获取到的是增强后的代理组件
	Calculator calculator = applicationContext.getBean(Calculator.class);
	//代理组件执行目标方法
	System.out.println("结果: " + calculator.div(10, 0));

	applicationContext.close();
}

2. 目标方法执行

2.1 代理组件执行目标方法流程

代理组件中保存了目标组件的详细信息,包括目标类的增强器列表,执行流程如下;

  • 根据ProxyFactory对象获取将增强器转成要执行的目标方法拦截器链;
  • 如果没有拦截器链,直接执行目标方法;
  • 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
    并调用 Object retVal =  mi.proceed();
  • 执行拦截器链;

2.2 增强器转成目标方法的拦截器链

执行目标方法,进入org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy)中:

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Class<?> targetClass = null;
	Object target = null;
	try {
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// May be null. Get as late as possible to minimize the time we
		// "own" the target, in case it comes from a pool...
		target = getTarget();
		if (target != null) {
			targetClass = target.getClass();
		}
		//将增强器转成目标方法的拦截器链
		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);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			// We need to create a method invocation...
			// 创建CglibMethodInvocation,执行目标方法和拦截器链
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		if (target != null) {
			releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

在转成拦截器链的过程中,如果是MethodInterceptor,直接加入到集合中,如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
	List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
	Advice advice = advisor.getAdvice();
	// 如果是MethodInterceptor,则直接加入集合
	if (advice instanceof MethodInterceptor) {
		interceptors.add((MethodInterceptor) advice);
	}
	//如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
	for (AdvisorAdapter adapter : this.adapters) {
		if (adapter.supportsAdvice(advice)) {
			interceptors.add(adapter.getInterceptor(advisor));
		}
	}
	if (interceptors.isEmpty()) {
		throw new UnknownAdviceTypeException(advisor.getAdvice());
	}
	return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}

得到的拦截器链集合的结果如下:

《Spring AOP原理之代理组件执行目标方法》

一个默认的ExposeInvocationInterceptor 和 4个增强器;

2.3 拦截器链和目标方法的执行

具体执行方法在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(),代码如下:

@Override
public Object proceed() throws Throwable {
	//	We start with an index of -1 and increment early.
	// 初始索引=-1
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		// 当interceptorsAndDynamicMethodMatchers为空或者 currentInterceptorIndex=interceptorsAndDynamicMethodMatchers.size()-1的时候,
		// 直接调用目标方法, invokeJoinpoint()里面实际是执行 method.invoke(target, args);
		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)) {
			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.
		// 调用拦截器的invoke方法;各个拦截器里面的执行其实是 调用自定义代码逻辑和还是调用该方法proceed();
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

拦截器和目标方法的执行流程如下图:

《Spring AOP原理之代理组件执行目标方法》

3. 总结

目标方法执行流程如下:

  • 代理对象执行目标方法;
  • CglibAopProxy.intercept();
    • 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor);
    • 利用拦截器的链式机制,依次进入每一个拦截器进行执行;
    • 效果:
      • 正常执行:前置通知-》目标方法-》后置通知-》返回通知;
      • 出现异常:前置通知-》目标方法-》后置通知-》异常通知
  • 执行结束;
    原文作者:AOP
    原文地址: https://blog.csdn.net/luojinbai/article/details/86728469
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞