飞道的博客

Spring 之 AOP 原理详解

482人阅读  评论(0)

AOP 概念

AOP(Aspect Oriented Programming)面向切面编程是 Spring 框架最核心的组件之一,它通过对程序结构的另一种考虑,补充了 OOP(Object-Oriented Programming)面向对象编程。在 OOP 中模块化的关键单元是类,而在 AOP 中,模块化单元是切面。也就是说 AOP 关注的不再是类,而是一系列类里面需要共同能力的行为。
在 AOP 中模块化单元是切面(Aspect),它将那些影响多个类的共同行为封装到可重用的模块中,然后你就可以决定在什么时候对哪些类的哪些行为执行进行拦截(切点),并使用封装好的可重用模块里面的行为(通知)对其拦截的业务行为进行功能增强,而不需要修改业务模块的代码,切面就是对此的一个抽象描述。

AOP 中有以下基础概念:

  • Join point(连接点):程序执行期间的某一个点,例如执行方法或处理异常时候的点。在 Spring AOP中,连接点总是表示方法的执行。
  • Advice(通知):通知是指一个切面在特定的连接点要做的事情。通知分为方法执行前通知,方法执行后通知,环绕通知等。许多 AOP框架(包括 Spring)都将通知建模为拦截器,在连接点周围维护一系列拦截器(形成拦截器链),对连接点的方法进行增强。
  • Pointcut(切点):一个匹配连接点(Join point)的谓词表达式。通知(Advice)与切点表达式关联,并在切点匹配的任何连接点(Join point)(例如,执行具有特定名称的方法)上运行。切点是匹配连接点(Join point)的表达式的概念,是AOP的核心,并且 Spring 默认使用 AspectJ 作为切入点表达式语言。
  • Aspect(切面):它是一个跨越多个类的模块化的关注点,它是通知(Advice)和切点(Pointcut)合起来的抽象,它定义了一个切点(Pointcut)用来匹配连接点(Join point),也就是需要对需要拦截的那些方法进行定义;它定义了一系列的通知(Advice)用来对拦截到的方法进行增强;
  • Target object(目标对象):被一个或者多个切面(Aspect)通知的对象,也就是需要被 AOP 进行拦截对方法进行增强(使用通知)的对象,也称为被通知的对象。由于在 AOP 里面使用运行时代理,所以目标对象一直是被代理的对象。
  • AOP proxy(AOP 代理):为了实现切面(Aspect)功能使用 AOP 框架创建一个对象,在 Spring 框架里面一个 AOP 代理要么指 JDK 动态代理,要么指 CgLIB 代理。
  • Weaving(织入):是将切面应用到目标对象的过程,这个过程可以是在编译时(例如使用 AspectJ 编译器),类加载时,运行时完成。Spring AOP 和其它纯 Java AOP 框架一样,是在运行时执行植入。
  • Advisor:这个概念是从 Spring 1.2的 AOP 支持中提出的,一个 Advisor 相当于一个小型的切面,不同的是它只有一个通知(Advice),Advisor 在事务管理里面会经常遇到。
  • Before Advice(前置通知):在某连接点(Join point)之前执行的通知,但是这个通知不能阻止连接点前的执行。
  • After Advice(后置通知):当某连接点(Join point)退出的时候执行的通知(不论正常返回还是异常退出)。
  • After Return Advice(返回后通知):当某连接点(Join point)正常完成的时候执行的通知,不包括抛出异常的情况。
  • Around Advice(环绕通知):包围一个连接点(Join point)的通知,类似 Web 中 Servlet 规范中的 Filter 的 doFilter 方法。可以在方法调用前后完成自定义行为,也可以选择不执行。
  • After Throwing Advice(返回后通知):当某连接点(Join point)抛出异常退出时执行的通知。

可以将多个通知应用到同一个目标对象上,即可以将多个切面织入同一个目标对象。
相比 OOP,AOP 有以下优点:

  • 业务代码更加简洁,例如当需要在业务行为前后做一些事情时候,只需要在该行为前后配置切面进行处理,无须修改业务行为代码。
  • 切面逻辑封装性好,并且可以被复用,例如我们可以把打日志的逻辑封装为一个切面,那么我们就可以在多个相关或者不相关的类的多个方法上配置该切面。

AOP 源码分析

关于 AOP 的使用有 XML 配置方式和注解配置方式,本文就不再阐述使用教程。

寻找入口

Spring 的 AOP 是通过接入 BeanPostProcessor 后置处理器开始的,它是 Spring IOC 容器经常使用到的一个特性,这个 Bean 后置处理器是一个监听器,可以监听容器触发的 Bean 声明周期事件。后置处理器向容器注册以后,容器中管理的 Bean 就具备了接收 IOC 容器事件回调的能力。
BeanPostProcessor 的使用非常简单,只需要继承并实现方法即可。

public interface BeanPostProcessor {
	//为在 Bean 的初始化前提供回调入口
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
     	return bean;
    }
	//为在 Bean 的初始化之后提供回调入口
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
     	return bean;
    }
}

这两个回调的入口都是和容器管理的 Bean 的生命周期事件紧密相关,可以为用户提供在 Spring IOC 容器初始化 Bean 过程中自定义的处理操作。
所以寻找 AOP 的入口,我们需要先定位到 BeanPostProcessor 执行的代码。即 AbstractAutowireCapableBeanFactory 类的 initializeBean 方法,在执行初始化方法前后调用 BeanPostProcessor 后置处理器的回调方法。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		//JDK的安全机制验证权限
		if (System.getSecurityManager() != null) {
			//通过匿名内部类根据实例化策略创建实例对象
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//将实例化的对象信息封装起来,如bean名称,类加载器,所属容器等信息
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		//调用BeanPostProcessor后置处理器的回调方法,在Bean实例初始化前做一些处理
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		//通过反射调用Bean实例的初始化方法,这个初始化方法是在init-method指定的
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		//调用BeanPostProcessor后置处理器的回调方法,在Bean实例初始化之后做一些处理
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

因为要生成目标对象的代理类,所以肯定是在 Bean 初始化方法执行之后做的操作。所以跟进 applyBeanPostProcessorsAfterInitialization 方法,可以看到遍历所有的 BeanPostProcessor 后置处理器中初始化后的处理方法。

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		//遍历容器为所创建的Bean添加所有BeanPostProcessor后置处理器
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//调用Bean实例所有的后置处理中初始化后的处理方法,为Bean实例对象在初始化之后做一些自定义的处理
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

BeanPostProcessor 是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在 Spring 中 BeanPostProcessor 的实现子类非常的多,分别完成不同的操作,如:AOP 面向切面编程的注册通知适配器、Bean 对象的数据校验、Bean 继承属性、方法的合并等等,我们以最简单的 AOP 切面织入来简单了解其主要的功能。下面我们来分析其中一个创建 AOP 代理对象的子类 AbstractAutoProxyCreator 类。该类重写了 postProcessAfterInitialization()方法。

选择代理策略

AbstractAutoProxyCreator 类的 postProcessAfterInitialization 方法,主要是进行判断早期暴露的引用 bean 对象是否等于当前 bean 对象,如果不是则重新生成代理对象。

	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

从这里我们可以看出,以上寻找 AOP 生成代理对象的入口是不准确的。为了解决属性注入的循环依赖问题,Spring 会在实例化对象之后、属性依赖注入之前先暴露 bean 对象。所以在 AbstractAutowireCapableBeanFactory 类的 getEarlyBeanReference 方法上就已经生成了代理对象,源码如下:

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

指向了 AbstractAutoProxyCreator 类的 getEarlyBeanReference 方法,通过源码我们可以看到一样是调用了 wrapIfNecessary 方法。所以可以确定 wrapIfNecessary 方法就是生成 AOP 代理类的入口。

	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

生成代理对象

继续追踪 wrapIfNecessary 方法,可以看到主要是对 bean 对象做判断是否需要生成代理类

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//判断是否应该代理这个Bean
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		/**
		 * 判断是否是一些InfrastructureClass或者是否应该跳过这个Bean,所谓InfrastructureClass就是指
		 * Advice、PointCut、Advisor等接口的实现类,shouldSkip方法默认返回false,子类可以覆盖
		 */
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		//获取这个Bean的通知,是否需要进行代理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//创建代理
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

根进 createProxy 方法, 主要对 ProxyFactory 做一些属性设置。

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		return proxyFactory.getProxy(getProxyClassLoader());
	}

整个过程跟下来,发现最终调用的是 proxyFactory.getProxy()方法。到这里大概能够猜到 proxyFactory 有 JDK 和 CGLib 的,那么该如何选择呢?

	public Object getProxy(@Nullable ClassLoader classLoader) {
		//获取代理类生成器并通过代理类生生成器生成代理对象
		return createAopProxy().getProxy(classLoader);
	}
	//获取 AOP 代理类生成器
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

跟踪 createAopProxy 方法可以看到是如何选择 JDK 或 CGLib 作为生成器,如果没有指定使用 Cglib 并且被代理类有接口的情况下使用 JDK 动态代理方式,否则使用 CGLib动态代理方式。在本文以 JDK 动态代理作为跟踪,如果对 JDK 动态代理不了解的同学可以看JDK动态代理实现原理

	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		//判断是否指定使用Cglib方式、是否有接口实现等来决定生成代理类的方式
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

获取到生成器之后,就调用 getProxy 方法获取代理对象。跟进到 JdkDynamicAopProxy 类的 getProxy 方法,如下:

	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		//获取指定代理对象的完整接口集
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		//检查接口集中有没有实现equals和hashcode方法
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		//创建代理对象,具体织入代码逻辑需要看invoke方法
		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 {
		Object oldProxy = null;
		boolean setProxyContext = false;

		//获取到bean容器实例化的源对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			//目标对象未实现equals
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				return equals(args[0]);
			}
			//目标对象未实现hashcode
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				return hashCode();
			}

			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			//直接反射调用Advised接口或者其父接口中定义的方法,不应用通知
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			//获得目标对象的类
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			//获取可以应用到此方法中的拦截器列表
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			
			//如果没有可以应用到此方法上的拦截器,则直接反射调用method.invoke
			if (chain.isEmpty()) {
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				//创建拦截链调用器
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				//开始执行拦截链及目标方法,返回方法结果
				retVal = invocation.proceed();
			}

			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				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()) {
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				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 方法来完成的,继续跟进:

	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		//注册一系列的AdvisorAdapter,用于将Advisor转化为MethodInterceptor
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		//存储可以应用到指定类或方法的拦截器
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		//查看是否包含IntroductionAdvisor
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//检查当前Advisor的切入点是否过滤掉了当前类
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					//检查当前Advisor的切入点是否可以匹配当前方法
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						//将Advisor转化为MethodInterceptor
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							//是否包装为动态方法匹配器
							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;
	}

我们来看看适配器是如何将Advisor转化为MethodInterceptor,源码如下:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

	private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}


	@Override
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		//.....
	}

	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		//对通知进行判断,获取实际的方法拦截器
		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[0]);
	}

	@Override
	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}

}

DefaultAdvisorAdapterRegistry 是 AdvisorAdapterRegistry 适配器的默认实现,创建过程中会先注入三个转换的具体适配器。在一开始我们已经说过有五种通知,分别是:

  • 前置通知
  • 后置通知
  • 返回后通知
  • 环绕通知
  • 异常通知

根据通知的具体作用,可以知道前置通知、返回后通知、异常通知是依赖于代理方法的执行时间段和结果的。而后置通知只要代理方法执行就必须调用,环绕通知可以决定什么时候调用代理方法。
我们先来看下这些通知的 UML 类图

可以看到 AdvisorAdapter 的作用就是创建具体的 MethodInterceptor,拦截器链就是由 MethodInterceptor 组成的。前置通知、返回后通知、异常通知需要由 AdvisorAdapter 适配器进行转换是为了方便后期依赖于代理方法不同时间段和结果的扩展。我们可以通过 AspectJAfterAdvice 类看到所有通知的具体实现。
到此我们明白了拦截器链(调用链)是如何生成的,接下来看看具体是如何调用的。由 ReflectiveMethodInvocation.proceed() 方法实现,生成 ReflectiveMethodInvocation 对象时已经对代理类、代理方法等数据进行保存。源码如下:

	protected ReflectiveMethodInvocation(
			Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
			@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

		this.proxy = proxy;
		this.target = target;
		this.targetClass = targetClass;
		this.method = BridgeMethodResolver.findBridgedMethod(method);
		this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
		this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
	}
	
	public Object proceed() throws Throwable {
		// 执行拦截器已经执行完,执行目标方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		//获取指定位置的拦截器
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		//是否需要进行动态匹配joinPoint
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			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 {
				// 跳过此拦截器并调用链中的下一个拦截器
				return proceed();
			}
		}
		else {
			// 它是一个拦截器,因此我们只需要调用它:切入点将在构造此对象之前进行静态评估。
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

可以很明显的看到这里使用的是责任链模式,层层往下执行,当所有的拦截器都执行完成后开始执行代理方法。如果需要依赖于代理方法的执行时间或结果的拦截器,具体代码实现在拦截器中。这里我们以 AfterReturningAdviceInterceptor 类进行分析,进入其 proceed 方法:

	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

因为当前是返回后通知,需要等代理方法执行完成后才能调用。所以返回到调用链上继续执行,获取到代理方法的执行结果后开始调用 AspectJAfterReturningAdvice.afterReturning() 方法:

	public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
		//仅在返回值是给定返回类型的实例和泛型类型参数(如果有)与赋值规则匹配的情况下才调用通知。如果返回类型为Object,则始终会调用
		if (shouldInvokeOnReturnValueOf(method, returnValue)) {
			invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
		}
	}

继续跟进 invokeAdviceMethod 方法可以看到调整到父类 AspectJAfterAdvice 中进行实现:

	protected Object invokeAdviceMethod(
			@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
			throws Throwable {
		//argBinding主要是按照通知方法的入参顺序拼接入参,然后调用通知方法
		return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
	}

	protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		//如果通知方法没有入参,就设置为null
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}

所有通知方法的执行最终都会走到 AspectJAfterAdvice.invokeAdviceMethod() 方法上,通过反射调用通知方法。

总结

本文从查找 AOP 入口开始层层分析源码到最后整个调用链的执行,希望能够帮助读者了解 AOP 的实现原理。AOP 常用场景有事务管理、日志打印、权限管理、性能监控等方面,了解 AOP 原理有利于读者在使用 AOP 时有更为深入的应用。


转载:https://blog.csdn.net/baidu_38083619/article/details/106406653
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场