Spring之AOP底层原理
如何创建一个切面类
只需要新建一个类,为它增加AOP切面注解@Aspect
就可以使用了。
在里面定义一些“增强方法”,然后通过@Before
、@After
、@AfterReturning
、AfterThrowing
、@Round
注解来指定何时执行方法的增强。
分别表示在方法之前、在方法之后、在方法正常返回后、在方法异常返回后、对方法进行包裹。
这里是一个@After
的实例,这里的@After
就等于@AfterReturning
加上@AfterThrowing
。在这5个注解中使用execution表达式进行增强范围的限定,可以精确到某些类的某些方法,写了这几个简单的注解之后,Spring的AOP就生效了。
运行原本的Bean方法,就会在方法执行之后触发编写的增强方法。
AOP具体如何在Spring中运行
在Spring启动的时候会创建IOC容器,同时将Spring中的bean进行三个连续的动作——构造、填充属性和初始化。
AOP功能就是通过Spring中一个专门处理AOP的“bean后置处理器”DefaultAutoProxyCreator进行方法增强的,可以算作IOC器官的附加功能。
所有的后置处理器都在bean构造完并且填充了属性之后执行,当然也包括我们的AOP后置处理器。
在每个Bean初始化之后,都会调用这个后置处理器的postProcessAfterInitialization方法:
在这个方法里,Spring会为需要使用AOP的bean创建代理对象。
先通过getAdvicesAndAdvisorsForBean方法获取所有的增强Advice。同时判断当前bean是否满足我们配置的切面条件。
如果满足条件的话,就会为这个bean构造“代理对象”来实现AOP。
为了更统一、更方便地构造代理对象,Spring会先搭建一个专门用来构造生产代理对象的工厂proxyFactory,Spring会告诉这个工厂具体选择哪种方式进行代理,分别是JdkProxy和Cglib。
程序员可以通过添加@EnableAspectJAutoProxy注解,并且将其中proxyTargetClass配置改为true,来强制使用Cglib。
在SpringBoot中默认使用的就是Cglib。不过,只有这个配置为false,同时该类实现了任意接口,才会使用JdkProxy,否则还是会使用Cglib方式。
proxyfactory知道使用哪种方式之后就会构造JdkDynamicAopProxy或者CglibAopProxy,然后就可以通过它们的getProxy方法获得真正的代理对象。
JdkProxy
先说相对简单而且即将被Spring无情放弃的JdkDynamicAopProxy。
在getProxy中会构造一个实现同样bean接口的代理对象,将真实bean作为代理对象中的一个成员变量。在调用bean方法的时候,就会执行代理对象中的invoke方法,这个invoke方法只有两步:
- 第一步,Spring会通过之前提到的“execution表达式”获取所有与该方法匹配的所有“增强方法”,并将它们组成调用链,同时进行排序。
- 第二步,就是开始按顺序执行这些调用链,这里的调用方式就是经典的“责任链模式”,在调用中间会插入并执行bean真实的方法。
Cglib
然后是最为常用的CglibAopProxy,同样会在getProxy方法中构造代理对象。用增强器Enhancer来设置代理基本信息以及增强方法的调用链。
接着执行Enhancer的create()方法来生成代理对象,和jdkDynamicAopProxy不同的是Cglib是基于jdk rt jar包中的ASM来生成一组新的.class文件,然后实例化它的对象。所以对于没有实现接口的bean也可以生成代理对象。
在调用bean方法时候会先执行代理对象的intercept方法,与jdkProxy一样也会通过责任链来执行所有的方法增强。
参考资料:史上最完整的AOP底层原理