24-Spring源码解析之AOP(3)——解析@Aspect获取增强器

Spring版本:<version>5.2.1.RELEASE</version>

上一篇:23-Spring源码解析之AOP(2)——AnnotationAwareAspectJAutoProxyCreator类源码

上一篇我们讲完了与AOP功能相关的四个问题中的两个问题:

  • 【问题一】为什么在配置类中写了 @EnableAspectJAutoProxy注解,Spring就为我们在容器中注册了一个AnnotationAwareAspectJAutoProxyCreator类的BeanDefinition
  • 【问题二】AnnotationAwareAspectJAutoProxyCreator类是什么,它的类结构是什么样子的
  • 【问题三】BeanDefinition只是Bean的定义信息,什么时候创建AnnotationAwareAspectJAutoProxyCreator
  • 【问题四】实现AOP功能与AnnotationAwareAspectJAutoProxyCreator类有什么关系

本篇文章要讲解【问题四】,但是问题四包含的内容比较多,因此会拆成两篇文章讲解。

在分析源码之前,我们可以先尝试着想一下,AOP功能的后续步骤若由我们实现,我们会怎么做?我觉得应该是这样的:

  • 【步骤一】解析切面类(即被@Aspect注解标注的类),将切面类中的增强器提取出来,放到beanFactory中管理
  • 【步骤二】创建每个Bean的时候都拦截一下,判断beanFactory中的增强器是不是用来增强当前Bean的,若是则创建当前Bean的代理,若不是就返回正常创建的普通Bean

实际上,Spring就是根据以上两个步骤来做的AOP功能。那么我们就开始去Spring中找一下每一个步骤是在Bean创建的什么时机做的吧。

一、解析@Aspect获取增强器

根据之前看过的Spring的源码,我们知道,注解解析都是通过Spring中的BeanPostProcessor完成的。那么我们先看一下该例子(例子在文章:22-Spring源码解析之AOP(1)——@EnableAspectJAutoProxy注解原理)中现在有的BeanPostProcessor

在这里插入图片描述
现在有6个BeanPostProcessor,而只有AnnotationAwareAspectJAutoProxyCreator类是与AOP功能有关的,因此一定是该类解析了@Aspect注解,那它在什么时候解析的呢?在上一篇文章中有提到AnnotationAwareAspectJAutoProxyCreator类所属的BeanPostProcessor类型。忘记了?不要紧,我再贴一遍。

在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator类是属于InstantiationAwareBeanPostProcessor类型的BeanPostProcessor。那我们想一下之前讲过的Bean生命周期中哪一步执行的是InstantiationAwareBeanPostProcessor类型的BeanPostProcessor

是在实例化Bean之前即createBean方法调用的resolveBeforeInstantiation方法中就执行了一次InstantiationAwareBeanPostProcessor类型的BeanPostProcessor

我原以为是容器初始化阶段创建切面类(getBean(LogAspects))的时候执行的解析@Aspect,但是经过一顿debug发现事情并不是这样!而是在容器初始化阶段创建配置类的时候就开始解析@Aspect了!这个地方一定要注意!

因此我们进入创建配置类时的createBean调用resolveBeforeInstantiation方法的地方。

在这里插入图片描述
我们进入resolveBeforeInstantiation方法
在这里插入图片描述
在本节最开始,给出了当前beanFactory中所有的BeanPostProcessor。这里我只抽取与该功能有关的部分代码进行讲解,与该功能无关的方法暂时省略。所以我们直接遍历到当前BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator时执行postProcessBeforeInstantiation方法。

这个时候由于上图中变量bp的类型为AnnotationAwareAspectJAutoProxyCreator,因此,这个时候调用的postProcessBeforeInstantiation方法为AnnotationAwareAspectJAutoProxyCreator父类AbstractAutoProxyCreator类中的postProcessBeforeInstantiation方法。

因为接下来的调用的方法是前面文章中没有分析过的方法,因此下面以代码的方式展示而非图片的方式展示。这样方便在代码中加入注释。

	// 这个属性很重要,其键为beanFactory中Bean的beanNmae,值为该类是否是被@Aspect注解标注的类
	private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
	
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			// 因为是第一次进入,因此advisedBeans中还不包含任何的cacheKey
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			// -------------------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 = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}
	

判断当前Bean是否是基础类型的AdvicePointcutAdvisorAopInfrastructureBean

	protected boolean isInfrastructureClass(Class<?> beanClass) {
		boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
				Pointcut.class.isAssignableFrom(beanClass) ||
				Advisor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass);
		if (retVal && logger.isTraceEnabled()) {
			logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
		}
		return retVal;
	}

postProcessBeforeInstantiation方法调用的shouldSkip是解析@Aspect获取增强器的核心方法,该方法是AspectJAwareAdvisorAutoProxyCreator类中的方法。下面我们详细讲解shouldSkip方法的功能。

二、AspectJAwareAdvisorAutoProxyCreator类的shouldSkip方法

	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// --------------------------------------【功能一】--2.1 详细讲解------------------------------------------------------ 
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
// --------------------------------------【功能二】--2.2 详细讲解------------------------------------------------------ 		
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

2.1 findCandidateAdvisors方法

该方法的功能:获取容器中所有增强器

findCandidateAdvisors方法的实现是在AspectJAwareAdvisorAutoProxyCreator类的子类AnnotationAwareAspectJAutoProxyCreator中实现的,因此我们继续跟踪到AnnotationAwareAspectJAutoProxyCreator类中的findCandidateAdvisors方法。

	protected List<Advisor> findCandidateAdvisors() {
		// 当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持
		// 在这里调用父类方法加载配置文件中的AOP声明(本例子使用的是AOP注解的方式,因此忽略这个方法的讲解)
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

在上篇文章中,创建时AnnotationAwareAspectJAutoProxyCreator,给AspectJAwareAdvisorAutoProxyCreatoraspectJAdvisorsBuilder属性赋了值。因此当执行findCandidateAdvisors时,这里的aspectJAdvisorsBuilder不为null

在这里插入图片描述

我们继续跟踪到this.aspectJAdvisorsBuilder.buildAspectJAdvisors()方法中。即BeanFactoryAspectJAdvisorsBuilder类的buildAspectJAdvisors方法。

	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<>();
// --------------------------------------------【功能一】--------------------------------------------					
					// 获取beanFactory中的所有beanName
					// 这一步骤中所有在beanFactory中注册的Bean都会被提取出来
					String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
							this.beanFactory, Object.class, true, false);
								
					// 遍历所有beanName,并找出声明@Aspect注解的类,进而找出对应的增强方法
					for (String beanName : beanNames) {
						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.
						Class<?> beanType = this.beanFactory.getType(beanName);
						if (beanType == null) {
							continue;
						}
// --------------------------------------------【功能二】--------------------------------------------						
						// 找到声明AspectJ注解的类
						if (this.advisorFactory.isAspect(beanType)) {
							aspectNames.add(beanName);
							// 用于存储被声明AspectJ注解的类 和 beanName
							AspectMetadata amd = new AspectMetadata(beanType, beanName);
							if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
										
// --------------------------------------------【功能三】--核心 2.2 详细介绍------------------------------------------
								// 对标记为AspectJ注解的类进行增强器的提取										
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

// --------------------------------------------【功能四】--------------------------------------------			
								// 将提取的结果加入到缓存!!!很重要!!!
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
					
								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();
		}
		// 若能执行到这一步,说明@AspectJ注解已经被解析过了,因此在这里直接从缓存中取出@AspectJ注解的类和对应的增强器即可。 		
		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;
	}
  • 【功能一】获取beanFactory中所有的Bean

在这里插入图片描述
我们可以看到,当前项目中beanFactory里有15个Bean,其中只有蓝色圈住的Bean为我们项目中的类对应的Bean,而只有beanNames[6]="logAspects"为被标注了@Aspect注解的类。

  • 【功能二】找到声明AspectJ注解的类:this.advisorFactory.isAspect(beanType)
	public boolean isAspect(Class<?> clazz) {
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}

	private boolean hasAspectAnnotation(Class<?> clazz) {
		return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
	}

至此,我们完成了Advisor的提取,在上面的步骤中最为重要也最为繁琐的就是【功能三】增强器的获取,而这一功能buildAspectJAdvisors方法将它委托给了getAdvisors方法去实现。

2.2 【功能三】this.advisorFactory.getAdvisors(factory)

我们看到调用this.advisorFactory.getAdvisors的时候传递进来了一个factory参数。先看一下传递进来的factory是什么

在这里插入图片描述
从上幅图片可以看出factory中包含beanFactorybeanName和被@Aspect注解标注的类的信息。

	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
		// 获取被`@Aspect`注解标注的类
		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		// 获取被`@Aspect`注解标注的类对应的beanName
		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<>();
		
// -------------------------------------------核 心-------------------------------------------	
		// 获取这个被`@Aspect`注解标注的类的所有方法	
// -------------------------------------------【功能一】---2.2.1 详细介绍----------------------------------------			
		for (Method method : getAdvisorMethods(aspectClass)) {
		
// -------------------------------------------【功能二】---2.2.2 详细介绍----------------------------------------			
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

// -------------------------------------------【功能三】------------------------------------------	
		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// 如果寻找的增强器不为空而且配置了增强延迟初始化那么需要在首位加入同步实例化增强器
			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
			advisors.add(0, instantiationAdvisor);
		}
// -------------------------------------------【功能四】------------------------------------------	
		// 获取DeclaredParents注解
		for (Field field : aspectClass.getDeclaredFields()) {
			Advisor advisor = getDeclareParentsAdvisor(field);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

		return advisors;
	}

函数中首先完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能回将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后是对DeclaredParents注解的获取。

下面我们主要介绍一下getAdvisors方法中的【功能一】和【功能二】的具体实现。

2.2.1 getAdvisorMethods

该方法的功能:获取这个被@Aspect注解标注的类的所有方法

	private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		final List<Method> methods = new ArrayList<>();
		// ---------------------------核心-----------------------------
		ReflectionUtils.doWithMethods(aspectClass, method -> {
			// 声明为PointCut的方法不处理
			if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
				methods.add(method);
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
		// 会对找到的所有方法进行排序
		methods.sort(METHOD_COMPARATOR);
		return methods;
	}
	public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
		// Keep backing up the inheritance hierarchy.
		// 获取当前类的所有方法。
		Method[] methods = getDeclaredMethods(clazz, false);
		// 遍历每个方法
		for (Method method : methods) {
			if (mf != null && !mf.matches(method)) {
				continue;
			}
			try {
				mc.doWith(method);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
			}
		}
		if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
			doWithMethods(clazz.getSuperclass(), mc, mf);
		}
		else if (clazz.isInterface()) {
			for (Class<?> superIfc : clazz.getInterfaces()) {
				doWithMethods(superIfc, mc, mf);
			}
		}
	}

在这里插入图片描述

现在我们获取到了被@Aspect注解标注的类的所有方法:5个。

接着我们看一下buildAspectJAdvisors的功能二getAdvisor

2.2.2 getAdvisor方法

该方法的功能:解析当前方法的切点注解根据注解信息生成增强器

我们在2.2.1节看到被@Aspect注解标注的类的所有方法:5个。但是由于我们不会去处理声明为PointCut的方法,所以真正到达getAdvisor方法进行处理的只有四个方法。如下所示:

在这里插入图片描述

我们以methods[0]为例,讲解 getAdvisor方法的实现过程。
先看一下传入getAdvisor方法中的参数值。
在这里插入图片描述
啥也不说,直接上getAdvisor源码

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

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// -------------------------------------------【功能一】---核心---------------------------------------	
		// 切点信息获取
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
// -------------------------------------------【功能二】---核心---------------------------------------	
		// 根据切点信息生成增强器
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

  • 【功能一】:切点信息获取
    • 所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("pointCut()")
	private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// -------------------------------------------【功能一】---下面详细讲解-------------------------------------
		// 获取方法上的注解
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}
		
// -------------------------------------------【功能二】------------------------------------------			
		// 使用AspectJExpressionPointcut示例封装获取的信息
		AspectJExpressionPointcut ajexp =
				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
				
// -------------------------------------------【功能三】------------------------------------------		
		// 提取得到的注解中的表达式					
		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
		if (this.beanFactory != null) {
			ajexp.setBeanFactory(this.beanFactory);
		}
		return ajexp;
	}

我们来看一下他是如何通过findAspectJAnnotationOnMethod方法获取方法上的注解的。

	// 设置敏感的注解类
	private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
		Pointcut.class, 
		Around.class, 
		Before.class, 
		After.class, 
		AfterReturning.class, 
		AfterThrowing.class};

	protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
		for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
			// 根据指定方法上的注解并使用AspectJAnnotation封装
			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
			if (foundAnnotation != null) {
				return foundAnnotation;
			}
		}
		return null;
	}

调用findAnnotation方法获取指定方法上的注解,并将注解和方法利用AspectJAnnotation封装起来

	private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(
											Method method, Class<A> toLookFor) {
		A result = AnnotationUtils.findAnnotation(method, toLookFor);
		if (result != null) {
			return new AspectJAnnotation<>(result);
		}
		else {
			return null;
		}
	}
  • 【功能二】:根据切点信息生成增强器
    • 所有的增强都是由Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl统一封装的

在这里插入图片描述

	public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, 
			int declarationOrder, String aspectName) {

// -------------------------------------------【功能一】--初始赋值----------------------------------------
		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
			// Static part of the pointcut is a lazy type.
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

			// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
			// If it's not a dynamic pointcut, it may be optimized out
			// by the Spring AOP infrastructure after the first evaluation.
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
		
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			
// -------------------------------------------【功能二】---核心---------------------------------------		
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}

在封装过程中只是简单地将信息封装在类的实例中,所有的信息单纯地赋值。 赋值的结果如下:

在这里插入图片描述
在实例InstantiationModelAwarePointcutAdvisorImpl进行初始化过程中还完成了对于增强器的初始化。因为不同的增强器所体现的逻辑是不同的,比如:@Before("pointCut()")@After("pointCut()")标签的不同就是增强器增强的位置不同,所以需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应得增强器就是在instantiateAdvice函数中实现的。

	private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
		Advice advice = this.aspectJAdvisorFactory.getAdvice(
																this.aspectJAdviceMethod, 
																pointcut,
																this.aspectInstanceFactory, 
																this.declarationOrder, 
																this.aspectName
															);
		return (advice != null ? advice : EMPTY_ADVICE);
	}

下面调用的方法就是真正根据不同类型的注解来获得不同的增强器了。

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

		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;

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

从上面可以看出,Spring会通过switch...case语句来根据不同的注解生成不同的增强器。例如,@Befroe对应case AtAfter,因此返回的springAdvice = new AspectJMethodBeforeAdvice(....)

以上,我们完成了获取增强器的功能。现在我们回到2.1findCandidateAdvisors方法节。在执行完以上的步骤后,2.1findCandidateAdvisors方法中的advosor的值变为:

在这里插入图片描述
至此,我们完成了shouldSkip()方法中调用的findCandidateAdvisors的分析。现在,我们回到二、AspectJAwareAdvisorAutoProxyCreator类的shouldSkip方法地方。这个shouldSkip只有两个功能。那么我们来看看第二个功能:

在这里插入图片描述
在这里插入图片描述

当前的类是配置类mainConfig_AOP,返回的candidateAdvisors中的advisorgetAspectName值都是logAsoects,因此这里的for循环不会return true。而是会执行当前类的父类的shouldSkip方法。而当前类的父类的shouldSkip方法始终返回false

至此,我们已经分析完了shouldSkip。我们回到调用shouldSkip的地方,即一、解析@Aspect获取增强器节,由于本文有点长,所以我把一节中调用shouldSkip的地方的代码粘贴过来:

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			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 = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

通过以上分析我们知道if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))的结果是false。因此往下执行,执行到最后返回null

三、总结

本篇文章的内容有些庞杂,本篇文章主要做的工作就是:解析@Aspect获取增强器,下面对解析过程做一个小结

在这里插入图片描述

记住:我们在解析@Aspect获取增强器的时候,将解析的结果放到了缓存中,我再把加入到缓存的地方贴出来一下:

	if (this.beanFactory.isSingleton(beanName)) {
		this.advisorsCache.put(beanName, classAdvisors);
	}

就是将解析好的被标注@Aspect注解的类和对应的增强器放到了advisorsCache中。在下一节我们会用到这个advisorsCache


至此,注解@Aspect的解析和增强器的获取就讲解完了,我们下一篇讲解:切面类和被切面类切入的类在创建Bean的时候AnnotationAwareAspectJAutoProxyCreator所作的事情。

发布了397 篇原创文章 · 获赞 71 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/xiaojie_570/article/details/104819921