源码分析-Spring AOP是如何实现的?(二)

接着上篇继续说Spring AOP,篇幅有限,上篇主要介绍了搭建Spring AOP的初始化环境,以及Spring实现这一功能的核心思路,这篇专门从源码分析Spring是如何实现AOP的。

AOP流程核心源码分析

此处分析源码也是按照我们之前所猜测的AOP实现步骤来逐条分析和验证。
看一下实例化我们的UserService前,Spring容器里都有什么?

源码分析-Spring AOP是如何实现的?(二)
可以看到,此时bean容器里只有切面类userAspect,要获取的userService,以及我们提前实例化好的BeanPostProcessor----AnnotationAwareAspectJAutoProxyCreator。仅仅3个对象,足够精简吧。

1.收集并解析切面

首先需要Spring能先从所有bean中识别出我们的切面类,AnnotationAwareAspectJAutoProxyCreator类重写的postProcessBeforeInstantiation方法就是专门处理这个问题的。跟着getBean进入实例化的流程,就会执行到下面代码处。

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		// 此处代码略过

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 实例化bean前,执行后置处理器,给我们一个干预Spring实例化操作的机会。
			// 如果返回对象,就不需要再执行后续的实例化操作。
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		// 准备实例化此对象
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		
		// 此处代码略过

	}
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					// 执行InstantiationAwareBeanPostProcessor后置处理器的方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						// 执行BeanPostProcessor的方法
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}
	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// 遍历所有的InstantiationAwareBeanPostProcessor对象,执行其实现的postProcessBeforeInstantiation方法
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

以上三段代码是IOC的必经流程,resolveBeforeInstantiation方法内回调InstantiationAwareBeanPostProcessor的后置处理器,这里可以直接返回一个对象给Spring容器,难点在这下面的逻辑,着重看看我们的AnnotationAwareAspectJAutoProxyCreator在其内部做了什么处理?

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		// 获取此类的key,一般就是对应的beanName。
		Object cacheKey = getCacheKey(beanClass, beanName);

		// 这里的targetSourcedBeans用于缓存通过自定义TargetSource创建出来的beanName。
		// 默认是没有自定义的,所以下面的判断默认都是true。
		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			// 这里的advisedBeans用于缓存所有已被解析过的bean,
			// key/value形式。value为true表示此bean是可以被代理的。false表示不需要被代理。
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// 此处主要判断此类是否为Aspect,如果是,则直接return,不需要解析。
			// isInfrastructureClass方法判断此Class是否为AspectJ提供的基础类
			// 基础类Advice/Pointcut/Advisor/AopInfrastructureBean不会被代理。
			// AspectJAwareAdvisorAutoProxyCreator类重写了部分逻辑,
			// 会通过isInfrastructureClass额外判断是否有@Aspect注解且此类没有被ajc编译器编译过
			// shouldSkip方法内部很复杂,不同的实现类会重写其中部分逻辑。
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		// 可以自定义TargetSource,其中包含着目标对象。
		// 除非我们自定义,默认是没有的。那么targetSource就会始终为null,下面if语句不会执行。
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			// 获取自定义的Advisor
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			// 根据自定义的Advisor创建代理对象
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			// 缓存解析过的bean
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

这个方法执行后就会提前找出所有的切面并生成Advisor数组缓存起来,核心逻辑在于其中的shouldSkip方法内。AnnotationAwareAspectJAutoProxyCreator类重写了部分逻辑,导致此方法内部很复杂,且其内部逻辑并不像方法名shouldSkip这么简单。此方法,只有此bean不是aspec切面,才会执行进去。由于我们这是实例化UserService,所以可以进入执行,一看究竟。

	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		// 查找候选的Advisors
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

这个方法核心在于findCandidateAdvisors方法,查找所有的Advisor。这算是AnnotationAwareAspectJAutoProxyCreator重写的逻辑,后面super.shouldSkip才会调用原来逻辑。

@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		// 获取Spring中实现了Advisor接口的bean
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		// Spring支持@Aspect注解,这里获取所有的@Aspect类bean,然后解析成Advisor.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

此方法其实就说明了两件事,其一,Spring支持原生Advisor接口。其二,AspectJ的影响力过大,于是Spring支持了AspectJ相关的注解,将其解析为Advisor。

这个findCandidateAdvisors方法内部会调用父类重写的此方法,看着名字一样,不要混乱。这里Spring会查找出容器内实现了Advisor接口的bean。

	/**
	 * Find all eligible Advisor beans in the current bean factory,
	 * ignoring FactoryBeans and excluding beans that are currently in creation.
	 * @return the list of {@link org.springframework.aop.Advisor} beans
	 * @see #isEligibleBean
	 */
	public List<Advisor> findAdvisorBeans() {
		// Determine list of advisor bean names, if not cached already.
		String[] advisorNames = this.cachedAdvisorBeanNames;
		// 查找容器内实现了Advisor接口的bean,将其名称缓存起来。
		if (advisorNames == null) {
			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the auto-proxy creator apply to them!
			advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.beanFactory, Advisor.class, true, false);
			this.cachedAdvisorBeanNames = advisorNames;
		}
		if (advisorNames.length == 0) {
			return new ArrayList<>();
		}

		// 遍历所有查找出来的Advisor bean。根据beanName获取其对应的bean对象。
		List<Advisor> advisors = new ArrayList<>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
				if (this.beanFactory.isCurrentlyInCreation(name)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					try {
						// 实例化Advisor对象
						advisors.add(this.beanFactory.getBean(name, Advisor.class));
					}
					catch (BeanCreationException ex) {
						Throwable rootCause = ex.getMostSpecificCause();
						if (rootCause instanceof BeanCurrentlyInCreationException) {
							BeanCreationException bce = (BeanCreationException) rootCause;
							String bceBeanName = bce.getBeanName();
							if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
								if (logger.isDebugEnabled()) {
									logger.debug("Skipping advisor '" + name +
											"' with dependency on currently created bean: " + ex.getMessage());
								}
								// Ignore: indicates a reference back to the bean we're trying to advise.
								// We want to find advisors other than the currently created bean itself.
								continue;
							}
						}
						throw ex;
					}
				}
			}
		}
		return advisors;
	}

由于我们并没有实现此接口,所以返回的就是空集合。

紧接着就会查找解析容器内标注了@Aspect注解的类。

	public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;

		if (aspectNames == null) {
			synchronized (this) {
				aspectNames = this.aspectBeanNames;
				if (aspectNames == null) {
					List<Advisor> advisors = new ArrayList<>();
					aspectNames = new ArrayList<>();
					// 获取容器内所有的beanName,这里真的很暴力。。。
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
					// 遍历容器内所有的beanName,构建Advisor。
					for (String beanName : beanNames) {
						// 这里默认是符合条件的bean,结果始终为fasle。
						if (!isEligibleBean(beanName)) {
							continue;
						}
						// We must be careful not to instantiate beans eagerly as in this case they
						// would be cached by the Spring container but would not have been weaved.
						// 根据beanName获取其Class类。
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
						// 这里是真正的判断节点,判断此类上是否有@Aspect注解,且没有被ajc编译器编译过。
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							// Spring作者的习惯,构建一个元信息方便后续操作。
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							// 这里涉及到Aspect框架的相关知识点,不太明白,看注释是判断AspectJ实例化的类型是否匹配。
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								// 构建一个能解析出Aspect元信息的工厂。
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								// 解析此Aspect,获取Advisor。
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								// 做缓存。
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								// 收集Advisor。
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
					return advisors;
				}
			}
		}

		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		// 这里在第二次在解析时,就可以从缓存中获取。
		List<Advisor> advisors = new ArrayList<>();
		for (String aspectName : aspectNames) {
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}

代码逻辑有点多,但不复杂。首先就是从容器内取出所有bean的beanName。然后遍历,获取其Class,利用反射判断其是否添加了@Aspect注解,如果是则要准备解析此类,将其中的每一个Advice都解析成Advisor,然后缓存起来。
下面我们就准备研究如何AspectJAdvisorFactory去调用getAdvisors方法解析此Class,返回Advisor。

	@Override
	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
		validate(aspectClass);

		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
		// so that it will only instantiate once.
		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

		List<Advisor> advisors = new ArrayList<>();
		// getAdvisorMethods获取此Class内所有的非Pointcut方法。@Pointcut注解标注的方法不是Advice。无法封装成Advisor。
		for (Method method : getAdvisorMethods(aspectClass)) {
			// 遍历非Pointcut方法,获取Advisor,如果此方法没有添加@BeforeAdvice等通知方法,则返回null。
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		// If it's a per target aspect, emit the dummy instantiating aspect.
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}

		// Find introduction fields.
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

getAdvisors方法核心逻辑主要就是获取此Class的所有没有标注@Pointcut注解的方法,然后遍历方法,每个方法都是一个Advisor。@Pointcut注解标注的方法仅表示一个切点,没有通知相关的代理逻辑。下面就看看具体根据Method创建Advisor的逻辑代码。

@Override
	@Nullable
	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		// 创建Pointcut对象,用于将来过滤要代理的bean。
		// 内部会判断,如果方法上没有[Pointcut.class, Around.class, Before.class, 
		// After.class, AfterReturning.class, AfterThrowing.class]任何一个通知注解,则返回null。
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
		
		// 根据切点Pointcut和Method对象等信息创建Advisor。
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

这里就接近真相了,可以看到,getAdvisor方法会根据Pointcut切点和Method对象以及切面元信息等创建一个Advisor。但是有一点还不清晰,我们都知道Advisor主要是由Pointcut和Advice构成的,Pointcut已经有了,那代理逻辑也就是Advice在哪里呢?查看InstantiationModelAwarePointcutAdvisorImpl的构造器创建对象过程。
这里我们debug看一下。
源码分析-Spring AOP是如何实现的?(二)
可以看到此Advisor内部维护了非常多的信息,其中包含了Pointcut对象,此Advisor所在的Class,所在的方法及名称,方法参数类型等信息。最下边的instantiatedAdvice就是此Advisor对应的Advice,它会在这个构造器内被创建,看一下创建过程。

	@Override
	@Nullable
	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		// 根据Aspect元信息获取此切面所在的Class类
		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);

		// 获取此方法上的通知注解
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		// 再一次校验是否有通知注解
		if (aspectJAnnotation == null) {
			return null;
		}

		// If we get here, we know we have an AspectJ method.
		// Check that it's an AspectJ-annotated class
		// 再一次校验是否为切面类
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		// 声明通知类
		AbstractAspectJAdvice springAdvice;

		// 重点,这里就会根据方法上注解的类型选择创建具体的Advice类
		// AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing中其中一个。
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method: " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

到这里就会发现,切面内的每一个通知方法都会被解析为一个Advice,具体的类型根据注解来决定。
如此,我们debug回到创建好的一个Advisor处观察结果。
源码分析-Spring AOP是如何实现的?(二)
如此,基本就完成了Aspect的解析和Advisor的创建。回到最开始我们的shouldSkip方法处,查看一下一共扫描出来多少个Advisor。

源码分析-Spring AOP是如何实现的?(二)
看一下debug级别下的日志。

2021-01-18 00:33:12 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory Found AspectJ method: public java.lang.Object com.binghuazheng.aop.config.UserAspect.adviceAround(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
2021-01-18 00:53:17 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory Found AspectJ method: public void com.binghuazheng.aop.config.UserAspect.adviceBefore(org.aspectj.lang.JoinPoint)
2021-01-18 00:53:28 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory Found AspectJ method: public void com.binghuazheng.aop.config.UserAspect.adviceAfter()
2021-01-18 00:53:28 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory Found AspectJ method: public void com.binghuazheng.aop.config.UserAspect.adviceAfterReturning()
2021-01-18 00:53:28 [main] DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory Found AspectJ method: public void com.binghuazheng.aop.config.UserAspect.adviceAfterThrowing(java.lang.Throwable)

可以确定,我们切面内的5个Advice方法都被解析成了Advisor。
如此,收集并解析Advisor的步骤就完成了,下面开始进入Bean的实例化步骤。

2.实例化Bean

这个步骤本质上就是IOC的过程,因为上面的解析Advisor过程仅仅是IOC流程中的一个后置处理器的方法中实现的,接下来Spring会通过此Bean对应的Class,使用构造器创建对象,然后进行依赖注入操作,直到执行到initializeBean方法处,就算bean实例化结束。

3.判断此Bean是否需要被代理

这里就要再一次进入到AnnotationAwareAspectJAutoProxyCreator这个类中,Spring判断此Bean是否需要被代理的执行节点是在initializeBean方法中BeanPostProcessor中的postProcessAfterInitialization方法中。我们跟代码看一看它是如何实现这部分功能的?
源码分析-Spring AOP是如何实现的?(二)
上面可以看到,程序执行到了BeanPostProcessor的postProcessAfterInitialization方法,此方法也可以说是IOC流程的最后一个阶段了。bean已经实例化且初始化方法执行完。我们已经拿到了目标对象userService。

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 判断是否非Aspect基础类,并且shouldSkip内部会查找收集所有Advisor。
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取此bean所匹配的Advisor
		// 如果没有合适的Advisor,说明此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;
	}

以上方法,判断是否需要被代理就在getAdvicesAndAdvisorsForBean方法中,他会找到此bean能匹配的Advisor,如果返回null,就不需要代理此对象。进入此方法内看看判断的逻辑。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 获取所有的Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 获取能匹配此Class的Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			// Advisor的排序,不同切面的Advisor执行顺序,这里就可以排出来。
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

上边方法第一行的findCandidateAdvisors()方法就是找到容器内所有的Advisor,第二行就是根据此bean的class,过滤这些Advisors。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		// 遍历所有Advisor,找到合适的Advisor
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			// 判断此Advisor是否匹配此Class
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

此方法基本可以看出,Spring会遍历所有的Advisors,然后通过canApply方法判断此Advisor是否匹配此Class。快接近真相了,进入canApply方法看一看。

	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		// 判断此Advisor内的Pointcut,此切点能否匹配此类
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		// 获取此切点的方法匹配器
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		// 某些自定义的切点,内部的方法匹配器是恒为true。那就直接返回true。不需要再逐个方法进行下面的匹配过滤。
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<>();
		// 此类可能已经被JDK代理,获取它的目标类Class
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		// 获取此目标类的所有接口Class
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		// 遍历所有的Class
		for (Class<?> clazz : classes) {
			// 反射获取所有的方法
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			// 遍历所有方法,开始进行方法匹配
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					// 有一个方法能满足此切点,就可以直接返回。
					return true;
				}
			}
		}

		return false;
	}

这里就可以看到Spring会先根据此切点,进行类的匹配,如果不匹配,则直接返回,不需要再执行后面方法的过滤;而后,就准备获取所有方法对象,逐个方法匹配,若有一个满足条件,则返回true,表明此Class类需要被代理。

源码分析-Spring AOP是如何实现的?(二)

好,可以看到满足条件的5个Advisor,再加上默认扩展添加的一个Advisor,一共6个Advisor。此bean是否需要被代理的判断这里就结束了,接下来就要开始执行代理过程了。

4.将目标对象变成代理对象

获取代理对象,需要需要使用代理工厂来选择具体类型的代理。因为面向接口编程么,默认一般我们使用JDK这种。当然也可以手动指定Cglib代理。Spring会根据你自己的目标类,自行判断使用什么代理。

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

		// 将此bean的beanClass缓存在其beanDefinition内,可用于获取此bean的原生Class
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		// 代理工厂,用于获取代理类,并设置一些基本的配置属性,比如代理方式等。
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		// 决定是否使用Cglib还是JDK
		if (!proxyFactory.isProxyTargetClass()) {
			// 这里除非提前设置beanDefinition,否则默认就是false
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				// 这里判断此Class是否有接口,添加可以代理的接口到proxyFactory
				// 如果没有接口,则设置ProxyTargetClass为true,表示使用Cglib方式。
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		// 这里会将所有的方法拦截器或Advice转换为Advisor。一般我们都是Advisor这种,不需要再转换包装。
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		// 添加Advisor
		proxyFactory.addAdvisors(advisors);
		// 添加目标类对象
		proxyFactory.setTargetSource(targetSource);
		// 自定义此代理工厂,默认不需要配置,可以重写此方法
		customizeProxyFactory(proxyFactory);
		// 冻结配置,不能再添加Advice。默认为false.
		proxyFactory.setFrozen(this.freezeProxy);
		// 预先过滤,后期再执行代理方法时,Pointcut的类过滤器匹配类时,可以短路匹配,直接执行方法匹配。
		// 默认为true,因为前面已经执行过类的匹配过滤,不需要重复执行。
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		// 执行动态代理
		return proxyFactory.getProxy(getProxyClassLoader());
	}

以上代码,仅仅是在代理前,做一些初始化配置,封装配置信息在ProxyFactory。我们都知道Spring的动态代理由由两种,JDK和Cglib。来看一看它是如何判断使用哪一种的。

	public Object getProxy(@Nullable ClassLoader classLoader) {
		// 选择具体的代理方式去获取代理对象
		return createAopProxy().getProxy(classLoader);
	}
@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// 判断使用JDK还是Cglib
		// isOptimize判断是否可以对此代理优化,默认false
		// isProxyTargetClass则可以通过应用注解配置,强制使用JDK或Cglib.默认false,JDK。
		// hasNoUserSuppliedProxyInterfaces主要判断是否实现了接口
		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.");
			}
			// 这里如果此Class是接口,或者已经继承了Proxy类,则可以使用JDK代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// 其它情况则使用Cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			// 面向接口编程,默认就是执行到此处,使用JDK动态代理。
			return new JdkDynamicAopProxy(config);
		}
	}

这里的判断逻辑很简单,如果不手动指定ProxyTargetClass代理方式,Spring就是根据hasNoUserSuppliedProxyInterfaces内部判断,会根据此Class的接口有无来判断JDK或Cglib,这里算是工厂加策略的体现吧。

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

这里可以看到,JDK动态代理就是如此呈现在我们面前,看着眼熟吧。
Cglib的太繁琐,但功能很强大,就不展示了。

5.将代理对象放入Spring容器

代理对象出来了,我们看一看它内部属性。

源码分析-Spring AOP是如何实现的?(二)
以上可以看到,它内部的代理逻辑就是JdkDynamicAopProxy类,此类实现了InvocationHandler,重写了其invoke方法。同时内部存储着ProxyFactory这个代理所需的各种信息,包括目标类,Advisor,接口等信息。

好了,代理对象已经有了,再往下就要将此bean方法Spring容器中,后续还要注入到其它bean。此过程是IOC的基本流程。我们直接看一看容器中有没有我们的代理对象吧。

源码分析-Spring AOP是如何实现的?(二)

6.调用代理对象方法

到这里,我们可以认为代理对象已经注入到其它bean,比如说已经注入到我们的Controller内,然后一个请求过来后,就会通过此代理对象调用JDK代理InvocationHandler的invoke方法。我们主要看看其实现JdkDynamicAopProxy的逻辑。
源码分析-Spring AOP是如何实现的?(二)
前面分析Spring实现思路时我们说过,Spring此时并不知道当前方法是否需要被代理,所以需要一个过程就是遍历所有的Advisors,判断每一个Advisor的Pointcut是否匹配此方法。此过程就在JdkDynamicAopProxy的invoke方法内。

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

		// TargetSource里有我们的目标类对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		// 下面几个特殊的方法,equals和hashCode方法等,如果目标类没有重写,则执行这里的逻辑。
		// 一般我们不代理这些方法。
		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			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,防止同一Service的两个代理方法直接调用,造成代理失效问题。
			// 默认不会暴露。
			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
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			// 这里会遍历之前存入ProxyFactory的Advisors,判断此方法是否需要被代理。
			// 找出匹配的Advisor,
			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.
			// 准备执行代理方法和目标方法
			// 这里如果找不到chain方法拦截器,说明此方法不需要被代理,执行下面逻辑,直接执行目标方法。
			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...
				// 如果有方法拦截器链,则要依次执行各种Advice
				// 已知代理对象,目标对象,目标方法,方法参数,目标类Class,方法拦截器链,基本就可以执行代理方法和目标方法了。
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 准备执行方法拦截器链里的各种Advice逻辑。
				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);
			}
		}
	}

上面this.advised.getInterceptorsAndDynamicInterceptionAdvice方法就是获取此方法匹配的MethodInterceptor chain,也就是方法拦截器。来看一看此方法的逻辑。

@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<Object>(config.getAdvisors().length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		// 遍历匹配此Class的所有Advisor
		for (Advisor advisor : config.getAdvisors()) {
			// 默认情况下,我们的Advisor都是此接口类型
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				// 判断是否匹配此Class,isPreFiltered之前创建代理类时,设置为true。因为已经判断过Class是否匹配,不需要再判断。
				// isPreFiltered会短路掉后面的判断条件
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					// 判断方法是否匹配
					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
						// 获取MethodInterceptor链
						// 这里会判断Advisor是否实现MethodInterceptor。
						// before通知/AfterReturn通知/throw通知,在此处会通过适配器转换为MethodInterceptor。
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						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) {
				// 这里应该是处理@DeclareParents这种注解的。功能挺强大,但用处不多。
				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;
	}

此方法内部,它会获取ProxyFactory中的Advisors,遍历所有的Advisors,先判断Pointcut是否匹配此Class,由于在获取代理对象时,已经提前判断过,所以这里就通过isPreFiltered直接过滤,不需要再次判断。紧接着就是进行方法的匹配判断,如果方法匹配成功,则根据Advisor获取MethodInterceptor对象。一般的Advice都已经实现了MethodInterceptor。只有@Before,@AfterReturning以及@AfterThrowing需要用适配器模式转换为MethodInterceptor,这样后期才能统一执行。

好,看一看我们这里有多少个MethodInterceptor。

源码分析-Spring AOP是如何实现的?(二)
算上第一个额外扩展的MethodInterceptor,正好6个。如果没有匹配到,就会进入第一个逻辑,执行原目标方法。

回到实际,接下来就要准备执行这些MethodInterceptor Chain了,具体各种类型的MethodInterceptor执行有点复杂,这里暂时不详细介绍,后续我会专门写一篇博客解释Advice也就是MethodInterceptor的调用链情况。

但有一点这里要知道,就是下面代码。

// We need to create a method invocation...
				// 如果有方法拦截器链,则要依次执行各种Advice
				// 已知代理对象,目标对象,目标方法,方法参数,目标类Class,方法拦截器链,基本就可以执行代理方法和目标方法了。
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// 准备执行方法拦截器链里的各种Advice逻辑。
				retVal = invocation.proceed();

如代码里注释,知道了这么信息,并且其中每个切面内的Advice方法,都可以在MethodInterceptor内部获取到,那代理功能就基本实现了。

总结

AOP的实现源码看起来很复杂,但如果心里面提前有个大概的实现思路,那debug时候,就不太容易迷失在代码中。Spring AOP在Spring框架中,非常重要,它是很多其它功能的实现基础,比如说事务,Spring的异步等功能都是利用AOP来实现的,所以掌握Spring AOP的实现还是很重要的。

上一篇:Spring Cloud + Spring Boot + Mybatis + Uniapp 企业架构之CAS SSO单点登录服务端环境搭建


下一篇:python开发_自己开发的一个小游戏