OOP(ObjectOrientedProgramming) 面向对象编程
AOP(AspectOrientedProgramming)面向切面编程
一、Aop简介
所谓的面向切面编程其实是对业务逻辑又进行了进一步的抽取,将多种业务逻辑中的公用部分抽取出来做成一种服务(比如事务管理、日志记录,性能统计,安全验证等),从而实现代码复用。另外这种服务通过配置可以动态的给程序添加统一控制,利用AOP可以对业务逻辑的各个部分进行分离,从而使得业务逻辑各部分之间的耦合度降低
Spring提供了四种各具特色的AOP支持
· 基于代理的经典AOP
· @AspectJ 注解驱动的切面
· 纯POJO切面
· 注入式AspectJ切面(适合Spring各个版本)
前面三中都是Spring基于代理的AOP变体,因此,Spring对AOP的支持局限于方法拦截。如果AOP需求超过了简单的方法拦截范畴,那么应该考虑在ASpectJ里实现切面,利用Spring的DI把Spring bean注入到ASpectJ切面中
二、AOP的相关概念:
1、Joinpoint:
在系统运行之前,AOP的功能模块都需要织入到OOP的功能模块中。所以,要进行这种织入过程,我们需要知道在系统的那些执行点上进行织入操作。这些将要在其上进行织入操作的系统执行点就称之为Joinpoint。(在Spring AOP 中仅支持方法级别的Joinpoint)
2、Pointcut:
代表的是Joinpoint的表达方式。将横切逻辑织入当前系统的过程中,需要参照Pointcut规定的Joinpoint信息,才可以知道应该往系统的哪些Joinpoint上织入横切逻辑。
Pointcut指定系统中符合条件的一组Joinpoint。
3、Advice:
是单一横切关注点逻辑的载体,代表将会织入到Joinpoint处的横切逻辑。如果将Aspect比作OOP中的Class,那么Advice就相当于Class中的Method。按照Advice在Joinpoint处执行时机的差异或者完成功能的不同,Advice可分成以下具体形式:Before Advice,After Advice(Afterreturning Advice、AfterThrowing Advice、AfterFinally Advice),Around Advice,Introduction。
4、Aspect:
是对体统中的横切关注点逻辑进行模块化封装的AOP概念实体。Aspect可以包含多个Pointcut以及相应的Advice定义。
5、织入:
完成横切关注点逻辑(以Aspect模块化的横切关注点)到OOP系统的过程。
三、Spring实现方式
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
重点关注动态代理技术
Spring的动态代理包括两个部分:
· JDK动态代理
JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
· CGLib动态代理
CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。
和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。
Spring AOP 框架对 AOP 代理类的处理原则是:
1. 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类(直接使用 JDK 提供的 Proxy 和 InvocationHandler);
2. 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。
四、Aop在xml中配置
1. <!-- 日志切面类 -->
2. <bean id="logAspectBean" class="com.zxf.aspect.LogAspect"/>
3. <!-- 第1步: AOP的配置 -->
4. <aop:config>
5. <!-- 第2步:配置一个切面 -->
6. <aop:aspect id="logAspect" ref="logAspectBean">
7. <!-- 第3步:定义切入点,指定切入点表达式 -->
8. <aop:pointcut id="allMethod"
9. expression="execution(* com.zxf.service.*.*(..))"/>
10. <!-- 第4步:应用前置通知 -->
11. <aop:before method="before" pointcut-ref="allMethod" />
12. <!-- 第4步:应用后置通知 -->
13. <aop:after-returning method="afterReturn" pointcut-ref="allMethod"/>
14. <!-- 第4步:应用最终通知 -->
15. <aop:after method="after" pointcut-ref="allMethod"/>
16. <!-- 第4步:应用抛出异常后通知 -->
17. <aop:after-throwing method="afterThrowing" pointcut-ref="allMethod"/>
18. <!-- 第4步:应用环绕通知 -->
19. <!--
20. <aop:around method="doAround" pointcut-ref="allMethod" />
21. -->
22. </aop:aspect>
23. </aop:config>