前言:
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 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 前置处理分析完毕。