AOP
AOP简介
AOP的底层是基于动态代理实现的,而动态代理实现有以下两种方式
- jdk动态代理:使用jdk中的Proxy,InvocationHanderl以及反射进行处理(jdk动态代理要求目标类必须实现接口)
- Oglib动态代理:第三方的工具库,创建代理对象,原理是继承,通过继承目标类,创建子类,但是目标类与方法都不是final的
动态代理可以在目标类源代码不改变的原来方法下进行更改,减少代码的重复,专注代码的逻辑,解耦合(使事务与非事务进行分离)
AOP:面向切面编程,可以使用以上的两种代理方法,把动态代理的实现步骤,方式都定义好了,让开发人员使用一种统一的方式
切面(Aspect):给目标类增加的功能就是切面,切面一般都是非业务方法,可以独立使用的。
AOP的使用注意事项:
- 什么功能下使用切面
- 合理安排切面的执行时间(哪一个方法之前,哪一个方法之后)
- 合理的安全切面的执行位置,对哪一类,哪一个方法增加功能
术语
Aspect:切面,表示增强的功能
JoinPoint:连接点,链接业务方法和切面的位置
PointOut:连接点方法的集合
目标对象:哪一个类增加功能
Advice:通知,切面功能执行的时间
AOP的实现
spring内部实现了AOP,在进行事务处理的时候使用了aop,但是在项目的开发的时候不使用spring的aop,springaop太过于笨重。我们经常使用aspectJ,一个专门做aop的框架,当然spring框架也集成了aspectj
切入点表达式(aspectj)
execution(权限名 返回值 方法名(参数))
execution(public * * (…)):指定切入点为任意公共方法
execution(* set*(…)):任意一个set方法
任意类中的任意方法,比如service包中的userservice的index方法
:在service包或者子包里面任意类的任意方法。..出现在类名的时候,后面必须跟*,表示包或者子包下面的所有类
:表示所有包service子包所有类(接口中所有方法都为切入点)
加入依赖项
1 | <dependency> |
注解
@Aspect是框架注解,表示当前的类是切面类,在此类中定义方法,要求是公共方法,方法名可以自定义,但是如果含有参数,只有一些参数类型卡哇伊使用
@Before前置通知注解
1 |
|
@AfterReturning后置通知
属性value表示切入点表达式,returning自定义变量,表示目标方法的返回值,自定义变量名必须和通知方法的形参名一样,当然也可以不接受返回值
1 | //res是目标方法的返回值,可以根据返回值做切面的处理,如果没有返回值则为空,Object res相当于首先执行了sayhi等方法,之后拿到返回值进行后续处理 |
@Around环绕通知
环绕通知必须含有一个返回值,此时发环绕通知首先调用时,不是执行测试中的方法,而是执行了这里定义的myAround方法
1 | /*可以在方法执行前,执行后都能增强功能,可以控制目标方法是否被执行,修改原来目标方法的执行结果,影响最后的调用 |
那么我们如何控制该方法是否执行那???
1 | JoinPoint表示切入点 |
1 | //我们可以对这个进行判断,再去决定是否调用原方法 |
当然我们也可以根据这个方法改变我们目标方法的返回值,环绕通知经常用于做事务,在执行前开启事务,执行完毕后关闭事务
@AfterThrowing
在程序发生异常时,执行的代码
1 |
|
@After
最终通知,总是会执行,可以用来清除资源,不管中间是否会发生异常
创建配置文件
1 | <!--声明目标--> |
测试
1 | public class AppTest |
可以看出,此时的对象已经不再是testservice对象了,而是jdk动态代理生成的。
@Pointcut注解
如果切入点表达式含有多个重复的切入点。可以 使用此注解
1 |
|
当别的使用时,可以直接进行引用
1 |
|
注意
此时我们使用接口,此时aop使用的是jdk的动态代理方式,如果我们去除接口,此时使用的是cglib的动态代理。当然如果我们使用接口,也仍旧可以使用cglib的动态代理方式,但是需要在xml文件进行配置
1 | <aop:aspectj-autoproxy proxy-target-class="true"/> |