NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

Spring AOP 深入了解(一)还给业务逻辑代码一个干净的世界

| Comments

本篇博客系列的目的:

之前一直想要实现一个日志类库:https://github.com/benweizhu/LoggerUtil

用来记录某个方法在调用前,调用后,抛出异常后的一些信息,比如方法名,参数,返回值。还希望可以指定记录的格式以及日志的级别(INFO,DEBUG等)。最关键的是,这个日志类库,必须有通用性和不可以有侵入性,这就导致它必定通过AOP来实现。

于是,为了做到这一点,现在我们就来深入的学习一次AOP:

为什么要AOP

编程语言最终极的目标就是能以更自然、更灵活的语言的方式模拟世界,从原始机器语言到过程语言再到面向对象的语言(OOP)。AOP提供了与OOP不同的另外一种方式来思考软件架构。OOP的模块单元是“类”,而AOP的模块单元“面”(Aspect)。

那么问题来了,什么是“面”?以及什么“面向切面编程”?

AOP被翻译成“面向方面编程”,“面向切面编程”,所以这里我更倾向于将“面”理解为“切面”(Aspect)。

从字面上理解,“切面”来自几何学,在立体几何中,切面是指用一个平面去截一个几何体(包括圆柱,圆锥,球,棱柱,棱锥、长方体,正方体等等),得到的平面图形。

那什么是“面向切面编程”?就是在该切面上加入一些逻辑操作(可以简单理解为“面向切面的操作”)。举个最常见的例子:

扑克牌的切牌,你可以将“广告牌”切入在任何你想要切入(或插入)的位置(你可以对扑克牌的任何一个切面做切牌操作)。插入的位置就是切面,插入的广告牌就是逻辑操作。

又或者是“斗地主”中,第一把不知道谁是地主,于是将一张牌反插入到牌的中间。本来应该按照顺序发牌,并不能知道谁是地主,但是因为你在某个位置插入了一个特殊操作(将一张牌反插入),因为多了一个逻辑,所以可以知道谁是地主。(或者将广告牌插入中间,也可以知道谁是地主)

这是“面向切面的编程”的最基础理解。

也许你还是不能理解面向切面编程,最重要是你并不知道为什么需要它,即何时需要它?

在OO的世界里,我们操作的是对象,创建一个对象并使用对象的属性和方法,而对象有抽象和继承的特性,因此,我们会利用抽象和继承的特性来消除重复的代码。

我们知道,编程语言是从原始机器语言到过程语言再到面向对象的语言,但是即便是OO的世界,我们也逃离不了面向过程的编程方式,代码的每一步操作一定是有顺序的,因为机器解释代码也是按顺序执行的。

代码按照顺序执行无可厚非,遇到重复的代码,我们利用抽象的方式,将重复的部分抽离成一个独立模块(方法或者类),由所有需要的地方重用即可。

但有一种顺序代码,它重复使用在不同的固定位置,它与业务代码无关,通过OO的常用办法并不能消除这种模式的重复,比如:事务管理,性能监控(和控制)。

1
2
3
4
5
public void addUser(){
  transactionManager.beginTransaction();
  ..
  transactionManager.commit();
}

我们知道这些重复性的代码逻辑,是可以非常轻松的独立出来,比如,beginTransaction和commit方法,但,我们无法通过抽象的方式来消除这种重复的调用,因为它和业务代码具有关联性,它依附在业务代码的顺序流程中。

有人说,可以采用模板方法(设计模式中的一种模式),这样可以消除重复,但也导致所有使用模板方法的类,都要重写模板中的其中一步(某个方法)来实现业务逻辑,重写方法是不能改变方法的名字。这样就给代码的自描述性带来了困难,得不偿失。

好在AOP希望做得到的就是,将这些分散在各个不同业务逻辑代码中的相同代码,通过切入的方式,将这块具有顺序性关联的逻辑抽离到独立模块,而在逻辑代码中将看不到之前重复的逻辑。

从而,还给业务逻辑代码一个干净的世界。这就是AOP给我们带来的好处。

参考资料:
1.Spring 3.0就是这么简单
2.http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/aop.html

Comments