深入理解 Spring AOP 源码分析(附源码分析)

前言:

Spring AOP 是一个非常常见的概念,使用了 Spring 的项目大多数也都用了 Spring AOP 的功能,比如我们常见的日志统计、事务管理等,AOP 的全称是 “Aspect Oriented Programming”,也是我们常说的⾯向切⾯编程,那你真的了解 Spring AOP 的原理吗?

AOP 基础知识

AOP 概念

  • 连接点(Join point):能够被拦截的地⽅、地点,Spring AOP 是基于动态代理的,所以是⽅法拦截的,每个成员⽅法都可以称之为连接点。
  • 切点(Poincut):匹配连接点的断言,在AOP中通知和一个切入点表达式关联,切点分为execution方式和annotation方式,前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。
  • 通知(Advice):在切面的某个特定的连接点上执行的动作,通知分为:前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)。
  • 织⼊(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时织入、类加载时织入、执行时织入
  • 引⼊/引介(Introduction):允许我们向现有的类添加新⽅法或属性,是⼀种特殊的增强。
  • 切面(Aspect):切⾯由切点和增强、通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。

通知(Advice)分类

  • 前置通知(Before Advice):在⽬标⽅法被调⽤前的通知功能。
  • 后置通知(After Advice):在⽬标⽅法被调⽤之后的通知功能。
  • 返回通知(After-returning):在⽬标⽅法成功执⾏之后的通知功能。
  • 异常通知(After-throwing):在⽬标⽅法抛出异常之后的通知功能。
  • 环绕通知(Around):把整个⽬标⽅法包裹起来,在被调⽤前和调⽤之后的通知功能。

理解 Spring AOP 之前需要对 Spring Bean 的创建过程及 Bean 生命周期有一定理解,相关知识传送门如下:

深入理解 Spring IOC 底层实现机制(refresh 方法源码分析)

Spring 源码之 BeanDefinition 加载分析

深入理解 Spring Bean 生命周期(附源码分析)

深入理解 Spring 循环依赖之三级缓存(附源码分析)

Spring AOP 实现原理概述:

  • 将所有切面保存在切面缓存中。
  • Bean 对象属性填充后,从切面缓存中取出所有方法和 Bean 对象的方法进行匹配,找到 Bean 对象的所有切面方法。
  • 创建 AOP 代理,有 JDK 动态代理和 Cglib 动态代理两种方式,Spring动态代理默认使用 CGlib。
  • 通过 责任链 + 递归 模式去执行切面逻辑。

Spring AOP 代码调用链路简图

简单梳理了 Spring AOP 从容器加载 Bean 到 Bean 的前置处理、创建代理对象、代理对象的调用的整个过程的代码调用链路图,Spring AOP 底层涉及到的代码非常多,简图只梳理了相对核心的步骤,Spring AOP 源码分析也会根据这个核心进行分析。

在这里插入图片描述

在这里插入图片描述

Spring AOP 源码分析

Spring 容器加载 Bean 相关的源码前面篇章有做过分析,就不在本篇进行分析了,感兴趣的伙伴可以通过传送门去看看,本篇核心点是分析 Spring AOP 相关源码。

Bean 前置处理

Bean 前置处理之 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 源码分析

AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 方法通过 RootBeanDefinition 相关属性,判断 Bean 是否有 BeanPostProcessor,是否是有应用程序自动生成(AOP),满足条件就继续调用 BeanPostProcessor 的前置处理。

//AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
//如果Bean配置了初始化前和初始化后的处理器 则试图返回一个需要创建Bean的代理对象,在这个方法中会判断对象是否存在
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   
	Object bean = null;
	//第一次进来  mbd.beforeInstantiationResolved 为 null Boolean 默认值为 null
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
   
		//mbd.isSynthetic():bean 是否是合成的 即未定义)(不是有代码生成) 由应用程序自动生成 例如 AOP 代理
		//hasInstantiationAwareBeanPostProcessors:是否有 bean 后置处理器
		if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
   
			//获取指定 beanName 的class
			Class<?> targetType = this.determineTargetType(beanName, mbd);
			if (targetType != null) {
   
				//在实例化前执行应用 bean 后置处理器 (后置处理器的前置处理 缓存切面)
				bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
   
					//bean 不为空 进行 bean 后置处理器的后置处理(AOP 生成代理对象)
					bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		//重新赋值 beforeInstantiationResolved
		mbd.beforeInstantiationResolved = bean != null;
	}

	return bean;
}

Bean 前置处理之 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation 源码分析

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation 方法是获取 Bean 所有的 BeanPostProcessor,然后调用 BeanPostProcessor 的 postProcessBeforeInstantiation 方法,执行 Bean 实例化的前置增强操作(缓存切面–本篇分析的重点)。

//AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
//调用指定 beanName 的所有 BeanPostProcessor 执行实例化前的后置处理方法
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   
	//从缓存中获取 bean 的后置处理器
	Iterator var3 = this.getBeanPostProcessorCache().instantiationAware.iterator();
	
	Object result;
	do {
   
		if (!var3.hasNext()) {
   
			return null;
		}
		//将 beanPostProcessor 转换为 InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor 接口
		InstantiationAwareBeanPostProcessor bp = (InstantiationAwareBeanPostProcessor)var3.next();
		//实例化前的后置处理
		result = bp.postProcessBeforeInstantiation(beanClass, beanName);
	} while(result == null);

	return result;
}

Bean 前置处理之 AbstractAutoProxyCreator#postProcessBeforeInstantiation 源码分析

AbstractAutoProxyCreator#postProcessBeforeInstantiation 先从缓存中获取指定 beanName 的 Bean,判断当前 Bean 是否已经执行过实例化前增强,以及一些相关判断,当前方法中的重点是 this.shouldSkip(beanClass, beanName) 方法。

//AbstractAutoProxyCreator#postProcessBeforeInstantiation
//bean 实例化前的后置处理
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   
	//尝试从缓存中获取 指定beanName 的 bean
	Object cacheKey = this.getCacheKey(beanClass, beanName);
	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
   
		//被增强的 bean 中是否有当前 bean 有的话 就不需要在增强了
		if (this.advisedBeans.containsKey(cacheKey)) {
   
			return null;
		}

		//this.isInfrastructureClass(beanClass):InfrastructureClass直译为“基础类型” 它指代的是IOC容器中注册的基础类 包括切面类、切入点、增强器等 bean 对象
		//this.shouldSkip(beanClass, beanName):是否需要跳过(被跳过的bean对象不会被提前增强) 本篇重点分析的方法
		if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
   
			//当前bean加入缓存中 表示不需要增强
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}
	//获取当前对象的自定义 targetSource 在创建代理对象的时候 会把当前对象包装成一个 targetSource 交给代理类 用于找到对象自身
	TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
   
		if (StringUtils.hasLength(beanName)) {
   
			//targetSource 不为空 beanName 不为空 beanName加入 自定义 targetSourcedBeans 中
			this.targetSourcedBeans.add(beanName);
		} 
		//获取指定 beanName 的通知过顾问(Advisors 是 spring 中 aop定义切面 通常由一个切点和一个通知组成(是通知的封装及延伸) aspect 是 AOP 规范切面  允许由多个切点和多个通知组成)
		Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
		//创建代理
		Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
		//加入缓存
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	} else {
   
		return null;
	}
}

Bean 前置处理之 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 源码分析

AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法是重点方法,来到这个方法里面,我们已经可以看到一些更 AOP 相关的概念了,比如增强器,也叫顾问的 Advisor,shouldSkip 方法会获取准备增强的 Bean 对象的所有增强器,遍历逐个检查当前准备增强的 bean 对象是否与增强器的名称一致,如果一致则跳过,不能被增强,也就是说 shouldSkip 方法要检查当前准备增强的 bean 对象是否是一个还没有经过任何代理的原始对象,检查的规则是根据 bean 对象的名称是否带有 .ORIGINAL 的后缀,如果是一个原始对象,则跳过不进行增强,我们会对 this.findCandidateAdvisors() 进行重点分析。

//AspectJAwareAdvisorAutoProxyCreator#shouldSkip
//是否跳过
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
   
	//查找 增强器 顾问 Advisor  重点分析的方法
	List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
	//迭代遍历
	Iterator var4 = candidateAdvisors.iterator();

	Advisor advisor;
	do {
   
		if (!var4.hasNext()) {
   
			//检查 beanName 代表的是不是原始对象
			return super.shouldSkip(beanClass, beanName);
		}

		advisor = (Advisor)var4.next();
		//advisor instanceof AspectJPointcutAdvisor:advisor 是否是 AspectJPointcutAdvisor 子类
		//(AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName):检查当前准备增强的 beanName 是否与增强器的名称一致
		//只有都满足的时候才增强
	} while(!(advisor instanceof AspectJPointcutAdvisor) || !((AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName));

	return true;
}

//AbstractAutoProxyCreator#shouldSkip
//AbstractAutoProxyCreator 是 AspectJAwareAdvisorAutoProxyCreator 的父类
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
   
    // 检查beanName代表的是不是原始对象(以.ORIGINAL结尾)
    return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}


Bean 前置处理之 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 源码分析

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法的作用就是获取增强器 Advisor,该方法会获取 Spring 的原生增强器和 AspectJ 切面增强器,我们重点分析  AspectJ 切面增强器,也就是 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 方法。

//AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
//查询增强器
protected List<Advisor> findCandidateAdvisors() {
   
	// 根据父类的规则添加所有找到的 Spring 原生的增强器
	List<Advisor> advisors = super.findCandidateAdvisors();
	//解析BeanFactory中所有的AspectJ切面,并构建增强器
	advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	return advisors;
}

Bean 前置处理之 BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors 源码分析

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors 方法会遍历所有的类,判断是否是切面,是切面才会进入切面的逻辑,进行一些列的相关判断,最终把切面缓存到增强器 advisorsCache 中缓存 ,至此 AOP Bean 前置处理分析完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值