Spring学习:Spring AOP
Spring AOP的概念
面向切面编程,是对面向对象编程(OOP)的一种补充
采用横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译和运行时,将提取出的代码应用到应该执行的地方
AOP的术语
- Aspect(切面):封装的用于横向插入系统功能的类
- joinpoint(连接点):一个应用执行过程中能够插入一个切面的点
- Pointcut(切入点):切面与程序流程的交叉点,即那些需要处理的连接点
- Advice(通知):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码.(可以理解为切面类中的方法)
- Target Object(目标对象):指所有被通知的对象,也成为增强对象
- Proxy(代理):将通知应用到目标对象之后,被动态创建的对象
- Weaving(织入):将切面代码插入到目标对象的过程
以下为我的通俗易懂的理解(重点):
如果把AOP 比喻为 事务Y 要插入 事务X
- 切面为 要插入的 Y
- 连接点为 X上可以被插入的点
- 切入点为 X上具体被Y插入的点
- 通知为 Y插入后,给X带来的东西(Y插入的代码)
- 目标对象为 被插入的X
- 代理为 插入后的X+Y
- 织入为 Y插入X的这个过程
AOP的动态代理
- JDK动态代理 局限性:动态代理的对象必须实现一个或多个接口
- CGLIB代理
- Spring代理工厂 使用ProxyFactoryBean
- 基于XML的声明式AspectJ
- 基于注解的声明式AspectJ(最常用)
基于XML的声明AspectJ
实例:
基于注解的声明式AspectJ(最常用)(重点)
- @Aspect 定义一个切面
- @Pointcut 定义切入点表达式
- @Before 定义前置通知
- @AfterReturning 定义后置通知 (这个才是后置通知,不要抓混了)
- @Around 定义环绕通知
- @AfterThrowing 定义异常通知 (异常时执行)
- @After 定义最终通知 (不管是否异常,都会执行)
- @DeclareParents 定义引介通知 (不要求掌握)
以下为代码实例:
@Aspect
@Component
public class MyAspect {
//删除 切入点
@Pointcut("execution(* com.tyut.frame.*Controller.delete(..))")
private void myPointCut(){}
//保存 切入点
@Pointcut("execution(* com.tyut.frame.*Controller.save(..))")
private void myPointCut2(){}
//删除环绕通知
@Around("myPointCut()")
public Object delAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("删除环绕开始");
Object object=proceedingJoinPoint.proceed();
System.out.println("删除环绕结束");
return object;
}
//添加环绕通知
@Around("myPointCut2()")
public Object saveAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("添加环绕开始");
Object object=proceedingJoinPoint.proceed();
System.out.println("添加环绕结束");
return object;
}
}
注意
- 如果在同一个连接点有多个通知需要执行,那么在同一切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的,目标方法之后的后置通知和环绕通知的执行顺序也是未知的
- Spring中的AOP代理默认就是使用JDK动态代理的方式来实现的
静态代理VS动态代理
-
静态代理—代理对象在编译时已经产生
【优点】代码结构清晰,易于理解和编写
【缺点1】一个代理类中的多个业务方法,代码重复
【缺点2】一个功能增强点就对应一个代理类
如果一个真实主题类中如果有多个功能增强点,就容易形成代理类的爆炸 -
动态代理—利用反射技术在程序运行时,才生成代理对象
【优点1】程序运行前,代理类事先不存在,使用时才创建和加载代理类 【优点2】功能增强的代码动态织入到真实主题的各个方法中,不会出现重复代码,可维护性强 【优点3】一个真实主题类的多个功能增强点都可以写在一个代理类中,不会引起代理类的爆炸 【缺点】代码编写复杂
动态代理的俩种实现
- 基于接口实现的动态代理
【核心API】JDK的Proxy类
【要求】真实主题类要实现接口,代理类实现了和真实主题相同的接口
- 基于子类继承的动态代理
【核心API】CGLIB第三库的Enhancer类
【要求】真实主题类不能使用final关键字修饰,因为代理类是继承了真实主题类的子类
AOP的工作原理
-
AOP使用动态代理技术为真实主题生成代理对象,代理对象在运行时将切面类中定义的方法动态织入到真实主题对象中,从而实现了对真实主题类的功能增强和扩展
-
JDK技术和CGLiB技术是Spring框架实现AOP的技术基础
如果真实主题类实现了接口,Spring会使用JDK动态代理技术,在程序运行时动态生成代理对象(该对象内部组合了目标对象),否则会使用CGLIB技术创建代理对象(该对象是目标对象的子类)