AOP(动态代理):指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方法;
导入AOP模块jar包
创建一个业务逻辑类MathCalculator,实现一个简单的除法
要实现的业务:在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常等等)
创建LogAspects类
通知方法:
前置通知(@Before):logStrat:在目标方法(div)运行之前运行
后置通知(@After):logEnd:在目标方法(div)运行结束之后运行
返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后通知
环绕通知(@aRound):动态代理,手动推进目标方法运行(joinPoint.procced())
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
添加注解:
对于传入两个int的参数方法进行切入
切入到该类的所有方法
创建一个统一的切入点值:
如果是内部方法使用,直接写上方法名;
如果是外部方法使用,写上全路径方法名;
接下来将切面类和业务逻辑类(目标方法所在类)都加入到容器中
现在我们得告诉spring哪个是切换类
因此我们在切换类上面加上@Aspact注解,通知IOC容器该类为切换类
传统方式开启切面模式
原理相同:现在我们的配置文件是MainConfigOfAOP类(等同于XML文件)
添加@EnableAspectJAutoProxy注解:开启切面模式
测试
添加打印信息
运行:
对于spring来说肯定不能new,直接 从IOC容器中获取
运行
我们也可以在相应的切换类中进行相应数据的获取和修改
总结:JoinPoint必须放到前面
运行结果:
AOP原理
1.@EnableAspectJAutoProxy
所以说整个AOP切面的核心在于@EnableAspectJAutoProxy
因此我们从@EnableAspectJAutoProxy入手分析它的底层
我们可以看到它的重点在于@Import注解
该注解导入了AspectJAutoProxyRegistrar
查看AspectJAutoProxyRegistrar类
该接口可以实现引入我们自定义组件 ,在我们之前的使用都是实现该接口的set方法,来自定义注册相应的bean
我们继续分析AspectJAutoProxyRegistrar类
在注册方法这里打上断点,来查看它的执行流程
我们可以看到调用了该方法
进入方法
继续进入方法
查看提示,我们可以看到它主要目的就是注册AnnotationAareAspectJAutoProxyCreator
由于是刚刚传入的没有参数,所以调用下面的
实现注册AnnotationAareAspectJAutoProxyCreator
回到之前,拿取注解@EnableAspectJAutoProxy的信息
总结来说:
给容器中注册了一个AnnotationAareAspectJAutoProxyCreator
分析AbstractBeanFactory,如下if语句中可以看到判断该bean是否存在,存在就执行下面代码,不存在就创建
创建bean:
1.先从缓存中获取当前bean,如果能获取到,说明bean是之前背创建过的,直接使用,否则再创建;只要创建好的bean都会被缓存起来
查看createBean:
希望后置处理器能够返回一个后置处理器
如果不能返回代理对象就继续往下操作:它里面内部就是三个创建bean的过程,可参考之前的beanPostProcessor
现在我们来分析当bean创建之后的流程:
看到它是通过CGLIB代理创建的
我们来到了CglibAopProxy类
获取目标中的拦截器链
如果没有拦截器链就直接执行
如果有的话
查看返回的chain的参数(增强拦截器)
总结:链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;拦截器链的机制,保证通知方法与目标方法的执行顺序。
1)、@EnableAspectJAutoProxy 开启AOP功能
2)、@EnableAspectJAutoProxy会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器的创建流程:
1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwared
2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
1)、创建业务逻辑组件和切面组件
2)、AnnotationAwareAspectJAutoProxyCreator拦截器组件的创建过程
3)、组件创建完之后,判断组件是否需要增强
是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象
5)、执行目标方法:
1)、代理对象执行目标方法
2)、CglibAopProxy.intercapt();
1)、得到目标方法的拦截器链(增强器包装成拦截器MethodIntercaptor)
2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
3)、效果:
正常执行:前置通知--》目标方法--》后置通知--》返回通知
出现异常:前置通知--》目标方法--》后置通知--》异常通知