AOP的相关理论介绍
1、AOP的介绍
AOP为Aspect Oriented Programming的缩写,即面向切面编程(也叫面向方面),是一种可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
编程思想 |
描述 |
---|---|
面向对象编程(OOP) | 简化代码:把重复代码纵向抽取到父类,OOP的三大特征继承、封装、多态,它主要是为了实现编程的重用性、灵活性和扩展性,强调的是类之间的层次关系 |
面向接口编程 | 解耦:不同组件之间解耦,即使一个组件改变了也不会影响其它的 |
面向切面编程(AOP) | 简化代码:把方法中的重复代码横向抽取到切面中,它是对方法的增强 |
2、为什么学习AOP
下面来分析一下面向对象编程(OOP)的局限性。
例如这里有两个类,两个类的方法1中的内容是重复的,而方法2是不重复的,此时我们就可以将方法1中的代码抽取出来放入父类中,这是典型的面向对象编程思想。
但是如果两个类的方法1中的内容只有部分是相同的,但是你又想将相同的方法抽取出来,这时再使用面向对象编程就无法实现了,因为相同的代码是存在于方法的内部,此时就可以使用AOP来实现了。
为了更好的理解OOP和AOP,下面简单举例说明:
①、定义一个简单的计算器类,内部功能为简单的加减乘除运算。
②、此时增加功能,给每个运算操作的前后都打印一下日志。
这样附加功能后,代码存在明显的问题:
- 代码会变得非常臃肿
- 核心逻辑的代码和非核心逻辑的代码混杂在一起,不利于开发和维护
- 将来不管是核心代码还是非核心代码想要升级或调试bug,都非常不便
而且这种情况也不能将相同的代码抽取出来放在父类中,但是可以用到AOP思想来解决。
③、使用AOP思想来解决上述问题,将不同的方法中相同的逻辑代码横向抽取出来,在使用时通过代理类织入到指定位置就能够完成特定的功能。
OOP与AOP对比
①相同点
- 都可以简化代码
②不同点
- 面向对象:纵向抽取
- 面向切面:横向抽取
AOP的总结:把『围绕』着目标代码的固定代码『抽取』出来,『封装』成固定的解决方案,哪里需要,套哪里。
3、AOP的应用场景
- 日志记录
- 事务处理
- 缓存处理
- 权限校验
- 性能统计
- 计数
- ......
4、AOP的实现原理(理论)
AOP的实现原理:基于动态代理完成,这个几乎人尽皆知。
动态代理是二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰。
动态代理有两种实现方式:
- JDK动态代理:需要被代理的目标类必须实现相应接口。利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
- CGlib动态代理:通过继承被代理的目标类实现代理,所以不需要目标类实现接口。利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
二者区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
细节补充(了解就好):如果AOP是通过JDK动态代理实现的,那么接口的实现类在应用了切面后,真正放在IOC容器中的是代理类的对象,目标类并没有被放到IOC容器中,所以根据目标类的类型从IOC容器中是找不到的,例如:ac.getBean(UserServiceImpl.class);
①、不使用代理与使用代理
②、生活中的代理
- 广告商找大明星拍广告需要经过经纪人
- 合作伙伴找大老板谈合作要约见面时间需要经过秘书
- 房产中介是买卖双方的代理
③、相关术语
- 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
- 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。
④、AOP中使用的是JDK代理还是CGLib代理
- 如果在AOP中被代理的是一个接口的实现类,那么AOP中使用就是JDK动态代理
- 如果在AOP中被代理的类是一个普通类,那么AOP中使用就是CGlib动态代理
5、AOP的相关术语
注意:AOP相关的术语不是唯一的,其实官方文档对这些术语的介绍也不是很清晰,它本身是不存在的,都是一些概念相关的东西,简单了解这些术语是什么意思就好。
AOP相关术语的整体截图:
术语 |
描述 |
---|---|
切面(Aspect) | 切面由切入点(Pointcut)和通知(Advice)组成,它既包括了横切逻辑的定义、也包括了连接点的定义,所以通常来说它是一个类,就是被@Aspect 注解注上的类。 |
通知/增强(Advice) | AOP在特定的切入点上执行的增强处理,也就是具体的横切逻辑。简单来说就定义了是干什么的,具体是在哪干。Spring AOP提供了5种Advice类型给我们:前置、后置、返回、异常、环绕,下面会详细介绍 |
连接点(JointPoint) | 目标类中每个成员方法都可以称之为连接点,一个连接点总是代表一个方法执行。可以这么理解:把方法排成一排,每一个横切位置看成x轴方向,把方法从上到下执行的顺序看成y轴,x轴和y轴的交叉点就是连接点。 |
切入点(Pointcut) | 定位连接点的方式。上面也说了,每个方法都可以称之为连接点,我们具体定位到某一个方法就称为切入点,在程序中主要体现为书写切入点表达式。切点分为execution 方式和annotation 方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。 |
织入(Weaving) | 就是通过动态代理,将通知添加到目标类的具体连接点上的过程。 |
目标(Target) | 表示被代理的目标对象。 |
代理(Proxy) | 表示向目标对象应用通知之后创建的代理对象。 |
通知/增强(Advice)中提供的五中类型(非常重要):
通知类型 | 描述 |
---|---|
前置通知(@Before) | 在我们执行目标方法之前运行。 |
返回通知(@AfterReturning) | 在我们的目标方法正常返回值后运行。 |
异常通知(@AfterThrowing) | 在我们的目标方法出现异常后运行。 |
后置通知(@After) | 在我们目标方法运行结束之后 ,不管有没有异常。 |
环绕通知(@Around) | 包括上面四种通知对应的所有位置。 |
为了方便理解上面的通知类型,下面结合try-catch-finally
模型举例: