阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

使用AOP

30次阅读
没有评论

共计 2391 个字符,预计需要花费 6 分钟才能阅读完成。

AOP 是 Aspect Oriented Programming,即面向切面编程。

那什么是 AOP?

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

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

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

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

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

public class BookService {public void createBook(Book book) {securityCheck();
        Transaction tx = startTransaction();
        try {// 核心业务逻辑
            tx.commit();} catch (RuntimeException e) {tx.rollback();
            throw e;
        }
        log("created book:" + book);
    }
}

继续编写updateBook(),代码如下:

public class BookService {public void updateBook(Book book) {securityCheck();
        Transaction tx = startTransaction();
        try {// 核心业务逻辑
            tx.commit();} catch (RuntimeException e) {tx.rollback();
            throw e;
        }
        log("updated book:" + book);
    }
}

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

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

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

public class SecurityCheckBookService implements BookService {private final BookService target;

    public SecurityCheckBookService(BookService target) {this.target = target;
    }

    public void createBook(Book book) {securityCheck();
        target.createBook(book);
    }

    public void updateBook(Book book) {securityCheck();
        target.updateBook(book);
    }

    public void deleteBook(Book book) {securityCheck();
        target.deleteBook(book);
    }

    private void securityCheck() {...}
}

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

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

如果我们以 AOP 的视角来编写上述业务,可以依次实现:

  1. 核心逻辑,即 BookService;
  2. 切面逻辑,即:
    1. 权限检查的 Aspect;
    2. 日志的 Aspect;
    3. 事务的 Aspect。

然后,以某种方式,让框架来把上述 3 个 Aspect 以 Proxy 的方式“织入”到 BookService 中,这样一来,就不必编写复杂而冗长的 Proxy 模式。

AOP 原理

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

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

  1. 编译期:在编译时,由编译器把切面调用编译进字节码,这种方式需要定义新的关键字并扩展编译器,AspectJ 就扩展了 Java 编译器,使用关键字 aspect 来实现织入;
  2. 类加载器:在目标类被装载到 JVM 时,通过一个特殊的类加载器,对目标类的字节码重新“增强”;
  3. 运行期:目标对象和切面都是普通 Java 类,通过 JVM 的动态代理功能或者第三方库实现运行期动态织入。

最简单的方式是第三种,Spring 的 AOP 实现就是基于 JVM 的动态代理。由于 JVM 的动态代理要求必须实现接口,如果一个普通类没有业务接口,就需要通过 CGLIB 或者 Javassist 这些第三方库实现。

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

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

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2391字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中