AOP 实现原理
一: 静态代理
-
实现了接口的
针对这样的类进行扩展功能,可以使用装饰者模式. -
没实现接口的
可以直接创建它的子类,进行扩展功能,也可以使用装饰者模式. -
使用AspectJ框架
-
弊端
使用1和2两种方式有一个很大的弊端,如果一个类或者接口方法过多,
写起来很麻烦,必须把所有的方法都进行扩展一遍.
想要解决这个问题,可以使用动态代理的方式.
二: 动态代理
-
使用JDK中反射包下的Proxy
前提: 目标类必须有实现的接口.- 获取类加载器
- 获取类所实现的所有接口
- 创建InvocationHandler实现类
- 调用Proxy.newProxyInstance方法,填入上面的参数,创建代理对象.
-
使用第三方的SGLib框架
前提: 目标类是final的- 创建Enhancer对象
- 设置类加载器
- 设置父类(实际上填的就是目标类)
- 设置Callback,方法中填入MethodInterceptor
- 调用Enhancer的create方法,创建代理对象.
三: 前提
如果一个类即是final的又没有实现接口,那么就无法对其进行扩展,
这个原则,不论是使用静态代理还是动态代理还是Spring的切面,
都是生效的.
四: 基本概念
面向切面编程(AOP)实际上就是在规定: 在何处何时执行什么代码.
-
接入点 JoinPoint
能增强的位置,在Spring中如果配置好了切面,切入点就是被增强了的方法. -
切点 Pointcut
实际上是一个表达式: execution(* com.lanou3g.demo..service..*(…))
这个表达式描述的就是对哪些切入点进行增强. -
通知 advice
-
前置通知 @Before
在接入点方法执行之前被调用的方法. -
后置通知 @After
在接入点方法执行之后被调用的方法,无论接入点方法是否抛出异常,都会执行. -
返回通知 @AfterReturning
在接入点方法正常执行之后被调用的方法,
也就是接入点方法没有抛出异常. -
异常通知 @AfterThrowing
在接入点方法抛出异常之后被调用的方法. -
环绕通知 @Around
最强的通知,可以在接入点方法的周围自定义任何功能,
集成了上面的四种通知.
-
在Spring中,1234的通知的方法参数中都可以添加一个JoinPoint类型的参数,
用来获取本次通知执行的时候接入点信息.
环绕通知的方法跟其他的方法有显著的不同,该方法必须有一个Object类型的返回值,
用来返回接入点方法的执行结果,该方法的参数是ProceedingJoinPoint类型.
返回通知,方法的参数中,可以额外增加一个Object类型的参数,
这个参数保存着接入点方法的返回值.
异常通知,方法的参数中可以额外增加一个Exception类型的参数,
用来获取本次接入点方法执行过程中抛出的异常.
- 切面
在Spring中就是一个类,类中保存着切点表达式和通知.
- 织入
将切面类与目标类进行整合的过程.
-
AOP配置
-
xml方式配置
- aop:config 导入aop的命名空间
- 在config里面声明切点表达式aop:point-cut
- 在config里面声明切面aop:aspect,在aspect的属性中指定切面的bean
- 在aspect里面声明通知aop:before,在before属性中指定切点表达式和切面bean中的方法
-
使用注解的方式配置
- aop:aspectj-autoproxy 开启注解方式的aop
- 新建切面类,添加@component,@Aspect注解
- 创建切点表达式方法,为方法添加@Pointcut注解,并在注解中填写切点表达式
- 创建通知方法,为通知方法添加某个通知注解:
@Before/@After/@AfterReturning/@AfterThrowing/@Around
并且在通知注解中指定某个切点表达式方法.
-