SpringAOP源码初探

一.调试环境搭建
  1. pom.xml
<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
  		<groupId>org.aspectj</groupId>
  		<artifactId>aspectjweaver</artifactId>
  		<version>1.8.7</version>
</dependency>
  1. Calculator类
@Component
public class Calculator {
	
	public int divide(int a,int b) {
		return a/b;
	}
	
}
  1. AppConfig类
@Configuration
@ComponentScan("com.xiaqi")
@EnableAspectJAutoProxy
public class AppConfig {

}
  1. LogAspect类
@Aspect
@Component
public class LogAspect {
	
	@Pointcut("execution(* com.xiaqi.service.Calculator.*(..))")
	public void pointCut() {}
	
	@Before("pointCut()")
	public void before() {
		System.out.println("我是前置通知!");
	}
	
	@After("pointCut()")
	public void after() {
		System.out.println("我是finally通知!");
	}
	
	@AfterReturning("pointCut()")
	public void afterReturning() {
		System.out.println("我是成功执行完之后通知!");
	}
	
	@AfterThrowing("pointCut()")
	public void afterThrowing() {
		System.out.println("我是异常之后的通知!");
	}
	
	@Around("pointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("我是环绕前置通知");
		Object result = joinPoint.proceed();
		System.out.println("我是环绕后置通知");
		return result;
	}
	
}
  1. AopEntry类(测试类)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class AopEntry {

	@Autowired
	private Calculator calculator;
	
	@Test
	public void test() {
		System.out.println(calculator.divide(4, 2));
	}
	
	
}

二.aop源码探析

aop核心是aop的自动代理创建器,所有有关的源码主要是与这个组件有关,所以aop需要弄清楚下面四个问题。

  • Aop自动代理创建器的注册
  • Aop自动代理创建器的创建
  • Aop自动代理创建器的作用时机
  • 产生的代理对象是如何发生作用的
1.Aop自动代理创建器的注册
  • 进入@EnableAspectJAutoProxy注解,发现这个注解通过@Import导入了一个类—>AspectJAutoProxyRegistrar,这个类实现了ImportBeanDefinitionRegistrar接口
    在这里插入图片描述
    在这里插入图片描述
  • 这个类的第45行代码向容器中注册了aop的自动代理创建器,跟进这个方法,发现这个方法调用了它下面的那个方法,向容器中注册了AnnotationAwareAspectJAutoProxyCreator这个类,这个类就是Aop的自动代理创建器,跟进这个注册方法
    在这里插入图片描述
  • 在这个方法的第138,142行,将这个创建器注册到容器中,自此Aop的自动代理创建器完成了注册
    在这里插入图片描述
2.Aop自动代理创建器的创建
  • 跟踪Aop自动代理创建器的创建之前,先看下它的继承体系,发现它实现BeanPostProcessor,BeanFactory和Ordered接口,可以看成这个创建器本质上是一个bean后置处理器

  • 进入到容器的refresh方法,这是IOC容器的启动的核心方法,详细可参考上一篇文章,初探Spring-IOC源码之普通单例bean的生命周期

  • 在refresh方法的第535行,调用registerBeanPostProcessors方法,跟进这个方法
    在这里插入图片描述

  • 在跟进第710行代码,方法spring将BeanPostProcessor分成了三类,即实现了PriorityOrdered接口的,实现了Ordered接口的以及其他剩余的bean后置处理器,由于aop的自动代理创建器实例Ordered接口,所以这个类第二轮注册中被注册。
    在这里插入图片描述
    在第226行调用了BeanFactory的getBean方法,最终创建这个AnnotationAwareAspectJAutoProxyCreator这个组件(详细过程可参考上一篇文章,初探Spring-IOC源码之普通单例bean的生命周期),最后被添加到BeanFactory中

3.Aop自动代理创建器的作用时机
  • 上面已经讲述到了aop的自动代理创建器本质上为BeanPostProcessor,所以它产生代理对象的核心方法应该为BeanPostProcessor两个后置处理方法中一个,先看postProcessBeforeInitialization方法(注意,AnnotationAwareAspectJAutoProxyCreator类中没有重写这两个方法,需要进入其父类AbstractAutoProxyCreator中)
    在这里插入图片描述
  • 发现postProcessBeforeInitialization方法并没有做任何处理,直接返回了bean,再查看postProcessAfterInitialization方法
    在这里插入图片描述
    跟进这个wrapIfNecessary方法
  • 在第355行,调用了createProxy方法,跟进
    在这里插入图片描述
  • 在第473行,调用getProxy方法,跟进
    在这里插入图片描述
  • 在第110行,跟进createAopProxy方法
    在这里插入图片描述
  • 在第105行,调用createAopProxy方法,跟进
    在这里插入图片描述
  • 在这个方法中,根据一些条件判断,产生了基于jdk的动态代理或者cglib的代理,至此aop的自动代理创建器完成了代理对象的创建
    在这里插入图片描述
4.通过代理对象调用目标方法
  • 在调用目标方法出打一个断点,按下F8将代码执行到这一行,再按F5跟进
  • 发现进入到代理对象的拦截方法,在第674行获取了拦截器链,可以查看下这个拦截器链,之前的五个通知方法被分别对应着五个对象
    在这里插入图片描述
  • 在第688行,开始调用拦截器链,跟进
    在这里插入图片描述
  • 发现currentInterceptorIndex从-1开始,先自增,然后从拦截链中去对应索引的拦截器,即第166行,最后在第185行进行调用,跟进第185行
    在这里插入图片描述
  • 发现在每个拦截器中都调用了mi.proceed()方法,回到了上一层中,继续获取下一个拦截器进行同样的调用,这里挑出几个通知方法来看看内部调用
    • afterThrowing通知(发现其实在方法外层加上了try-catch):
      在这里插入图片描述
    • afterReturning通知:
      在这里插入图片描述
    • after通知(其实就是在方法外层增加了try-finally):
      在这里插入图片描述
  • 当最终所有的拦截器被调用后,即currentInterceptorIndex == 拦截器数-1时,调用目标方法。这时可以查看debug栈,发现将所有的拦截器的调用方法都压栈了。
    在这里插入图片描述
  • 最终,通过代理对象调用目标方法的执行流程可总结为下图:
    在这里插入图片描述
    执行顺序:
  1. 正常执行(不发生异常,around通知调用ProceedingJoinPoint.proceed()方法放行):
    环绕前置通知---->前置通知---->目标方法---->环绕后置通知---->后置通知(after)---->返回之后的通知(afterReturning)
  2. 发生异常:
    环绕前置通知---->前置通知---->目标方法---->后置通知(after)---->异常通知(afterThrowing)
  3. around通知不调用ProceedingJoinPoint.proceed()方法:
    环绕前置通知---->环绕后置通知---->后置通知(after)---->返回之后的通知(afterReturning)
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值