Spring AOP 超详细源码解析

知识章节

Spring AOP 超详细源码解析_第1张图片

基础知识

什么是 AOP

  • AOP 的全称是 “Aspect Oriented Programming”,即面向切面编程
  • 在 AOP 的思想里面,周边功能(比如性能统计,日志,事务管理等)被定义为切面,核心功能和切面功能分别独立进行开发,然后把核心功能和切面功能“编织”在一起,这就叫 AOP
  • AOP 能够将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性

AOP 基础概念

  • 连接点(Join point):能够被拦截的地方,Spring AOP 是基于动态代理的,所以是方法拦截的,每个成员方法都可以称之为连接点
  • 切点(Poincut):每个方法都可以称之为连接点,我们具体定位到某一个方法就成为切点
  • 增强/通知(Advice):表示添加到切点的一段逻辑代码,并定位连接点的方位信息,简单来说就定义了是干什么的,具体是在哪干
  • 织入(Weaving):将增强/通知添加到目标类的具体连接点上的过程
  • 引入/引介(Introduction):允许我们向现有的类添加新方法或属性,是一种特殊的增强
  • 切面(Aspect):切面由切点和增强/通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。

  • AOP 五种通知分类
    • 前置通知(Before Advice):在目标方法被调用前调用通知功能
    • 后置通知(After Advice):在目标方法被调用之后调用通知功能
    • 返回通知(After-returning):在目标方法成功执行之后调用通知功能
    • 异常通知(After-throwing):在目标方法抛出异常之后调用通知功能
    • 环绕通知(Around):把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能

AOP 简单示例

创建一个配置类,开启 AspectJ 的自动代理功能

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.aspectj")
public class DemoAspectJConfig {
	// @EnableAspectJAutoProxy 开启注解 aop 功能
	// 向 spring 容器中注册 AnnotationAwareAspectJAutoProxyCreator
}

新建接口和接口实现类

// 接口
public interface DemoDao {
	void query();
}

// 实现类
@Component
public class DemoDaoImpl implements DemoDao {
	@Override
	public void query() {
		System.out.println("query ......");
	}
}

创建一个切面

@Aspect
@Component
public class DemoAspect {
	// 配置切点
	@Pointcut("execution(* com.aspectj.dao.*.*(..))")
	public void point(){
	}
	// 切点通知
	@Before("point()")
	public void beforeAdd(){
		System.out.println("before-------------");
	}
}

创建启动类

public class TestAspect {
	public static void main(String[] args) {
		// 刷新容器
		AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(DemoAspectJConfig.class)
		// 获取 bean 对象
		DemoDao dao = configApplicationContext.getBean(DemoDao.class);
		// 代理对象执行
		dao.query();
	}
}

启动 main() 方法,可以看到输出的内容,AOP 配置方法执行
Spring AOP 超详细源码解析_第2张图片


Spring AOP 执行流程

Spring AOP 超详细源码解析_第3张图片

源码解读

代码入口

Spring AOP 超详细源码解析_第4张图片
Spring AOP 超详细源码解析_第5张图片
Spring AOP 超详细源码解析_第6张图片

Spring AOP 超详细源码解析_第7张图片

前置处理

判断是否是切面

Spring AOP 超详细源码解析_第8张图片
Spring AOP 超详细源码解析_第9张图片
Spring AOP 超详细源码解析_第10张图片
Spring AOP 超详细源码解析_第11张图片
Spring AOP 超详细源码解析_第12张图片
Spring AOP 超详细源码解析_第13张图片
Spring AOP 超详细源码解析_第14张图片
构建 bean 对象 advisors 流程
① 遍历所有的类
② 判断是否切面,只有切面才会进入后面逻辑
③ 获取每个 Aspect 的切面列表
④ 保存 Aspect 的切面列表到缓存 advisorsCache
Spring AOP 超详细源码解析_第15张图片

获取切面列表

Spring AOP 超详细源码解析_第16张图片
Spring AOP 超详细源码解析_第17张图片
Spring AOP 超详细源码解析_第18张图片
Spring AOP 超详细源码解析_第19张图片
Spring AOP 超详细源码解析_第20张图片
Spring AOP 超详细源码解析_第21张图片
到这一步,前置处理已经完成 !

后置处理

获取切面

Spring AOP 超详细源码解析_第22张图片
Spring AOP 超详细源码解析_第23张图片
Spring AOP 超详细源码解析_第24张图片
Spring AOP 超详细源码解析_第25张图片

创建代理对象


Spring AOP 超详细源码解析_第26张图片
对象增强处理流程
① 获取当前 bean 对象 advisors 列表,判断是否为空
② 不为空就创建代理对象

Spring AOP 超详细源码解析_第27张图片
Spring AOP 超详细源码解析_第28张图片
Spring AOP 超详细源码解析_第29张图片
Spring AOP 超详细源码解析_第30张图片
Spring AOP 超详细源码解析_第31张图片
Spring AOP 超详细源码解析_第32张图片
Spring AOP 超详细源码解析_第33张图片
Spring AOP 超详细源码解析_第34张图片
Spring AOP 超详细源码解析_第35张图片
Spring AOP 超详细源码解析_第36张图片
Spring AOP 超详细源码解析_第37张图片
Spring AOP 超详细源码解析_第38张图片
Spring AOP 超详细源码解析_第39张图片
Spring AOP 超详细源码解析_第40张图片
Spring AOP 超详细源码解析_第41张图片
Spring AOP 超详细源码解析_第42张图片

切面执行

Spring AOP 超详细源码解析_第43张图片
Spring AOP 超详细源码解析_第44张图片
实例化 ReflectiveMethodInvocation 对象,调用 proceed() 方法 Spring AOP 超详细源码解析_第45张图片
Spring AOP 超详细源码解析_第46张图片

第一次递归

数组的第一个对象是 ExposeInvocationInterceptor,执行 invoke(),注意入参是 ReflectiveMethodInvocation
Spring AOP 超详细源码解析_第47张图片


第二次递归

数组的第二个对象是 MethodBeforeAdviceInterceptor,执行 invoke()
Spring AOP 超详细源码解析_第48张图片


Spring AOP 超详细源码解析_第49张图片


第三次递归

如果 advisor 有后置处理,就执行第三次递归


跳出递归

Spring AOP 超详细源码解析_第50张图片

总结

  • AOP 实现原理
    • 将所有的切面都保存在缓存中
    • 取出缓存中的切面列表,和 bean 对象的所有方法匹配,拿到属于 bean 对象的切面列表
    • 创建 AOP 代理对象
    • 通过 “责任链 + 递归”,去执行切面逻辑

你可能感兴趣的:(Spring,spring,java)