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
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值