那什么是AOP?

    我们先回顾一下OOP:Object Oriented Programming,OOP作为面向对象编程的模式,获得了巨大的成功,OOP的主要功能是数据封装、继承和多态。

    而AOP是一种新的编程方式,它和OOP不同,OOP把系统看作多个对象的交互,AOP把系统分解为不同的关注点,或者称之为切面(Aspect)。

    要理解AOP的概念,我们先用OOP举例,比如一个业务组件,它有几个业务方法:

    • createBook:添加新的Book;
    • deleteBook:删除Book。

    对每个业务方法,例如,createBook(),除了业务逻辑,还需要安全检查、日志记录和事务处理,它的代码像这样:

    对于安全检查、日志、事务等代码,它们会重复出现在每个业务方法中。使用OOP,我们很难将这些四处分散的代码模块化。

    考察业务模型可以发现,BookService关系的是自身的核心逻辑,但整个系统还要求关注安全检查、日志、事务等功能,这些功能实际上“横跨”多个业务方法,为了实现这些功能,不得不在每个业务方法上重复编写代码。

    一种可行的方式是使用,将某个功能,例如,权限检查,放入Proxy中:

    这种方式的缺点是比较麻烦,必须先抽取接口,然后,针对每个方法实现Proxy。

    另一种方法是,既然的代码都是标准的Proxy样板代码,不如把权限检查视作一种切面(Aspect),把日志、事务也视为切面,然后,以某种自动化的方式,把切面织入到核心逻辑中,实现Proxy模式。

    • 核心逻辑,即BookService;
    • 切面逻辑,即:
    • 日志的Aspect;
    • 事务的Aspect。 然后,以某种方式,让框架来把上述3个Aspect以Proxy的方式“织入”到BookService中,这样一来,就不必编写复杂而冗长的Proxy模式。

    如何把切面织入到核心逻辑中?这正是AOP需要解决的问题。换句话说,如果客户端获得了的引用,当调用bookService.createBook()时,如何对调用方法进行拦截,并在拦截前后进行安全检查、日志、事务等处理,就相当于完成了所有业务功能。

    在Java平台上,对于AOP的织入,有3种方式:

    • 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ就扩展了Java编译器,使用关键字aspect来实现织入;
    • 运行期:目标对象和切面都是普通Java类,通过JVM的动态代理功能或者第三方库实现运行期动态织入。 最简单的方式是第三种,Spring的AOP实现就是基于JVM的动态代理。由于JVM的动态代理要求必须实现接口,如果一个普通类没有业务接口,就需要通过CGLIB或者这些第三方库实现。

    AOP技术看上去比较神秘,但实际上,它本质就是一个动态代理,让我们把一些常用功能如权限检查、日志、事务等,从每个业务方法中剥离出来。

    需要特别指出的是,AOP对于解决特定问题,例如事务管理非常有用,这是因为分散在各处的事务代码几乎是完全相同的,并且它们需要的参数(JDBC的Connection)也是固定的。另一些特定问题,如日志,就不那么容易实现,因为日志虽然简单,但打印日志的时候,经常需要捕获局部变量,如果使用AOP实现日志,我们只能输出固定格式的日志,因此,使用AOP时,必须适合特定的场景。

    读后有收获可以支付宝请作者喝咖啡,读后有疑问请加微信群讨论:

    使用AOP - 图1