Magic AOP:面向切面的业务日志框架设计,第一部分

        本文的设计方案来源于一个真实的软件开发项目,并经过了该项目的初步验证,现记录下来供大家讨论,并试图引发关于面向方面软件设计(AOSD)的一些更深层次的思考,以期集思广益并获得更加完美的解决方案。<o:p></o:p>

1.      简介

业务日志在企业级的软件系统中是不可或缺的功能,它的关注点与我们日常熟悉的系统日志有着一些本质的区别:

<o:p></o:p>

1.       系统日志主要关注应用程序自身的运行状态,通常用于应用程序的调测跟踪和崩溃恢复,其分类也按照这种理念(TRACEDEBUGINFOWARNERRORFATAL)来划分,而业务日志主要关注业务本身的执行状态,通常用于业务的执行状态记录、分类检索、崩溃恢复以及业务安全;

2.       系统日志一般没有分类查询的需求,其记录介质可以是任何一种可存储的媒介,如文件、数据库、电子邮件等,目前常用的一些日志组件也没有内建对日志进行查询的功能支持;

<o:p></o:p>

一般的介绍AOP的技术文章都喜欢把系统日志记录作为AOP的一个经典示例,但这只是一个美好的愿望,以"系统日志"作为一个方面来切入粒度似乎太大了,系统日志的细粒度和无规律性决定了其切入点难以描述,关注点难以定位,唯一的方式是将“系统日志”关注点进一步拆解,一直拆解到可以接受的程度,如果我们的项目足够小,这种做法或许可行。但很不幸,我们的项目很大,要经过相当多的分解才能最终找到日志的规律性。我们还是可能需要成百上千条语句来指定切入点的位置,最终的结果将很难维护,这样的做法对于一个企业级的系统而言是脆弱乃至于不可接受的。况且,像Debug这样的Log级别,无论你怎样拆解,都不可能找到完美的规律。通常,任何一个系统中的Log都会保持逻辑的一致性,如果经过了这样的层层分解,Log作为一个逻辑主体的完整性被完全破坏了。这是一种为了AOPAOP的做法,非但工作量没有减轻,还带来了无穷的后患。

<o:p></o:p>

现在我们再来关注业务日志,我们在上面比较系统日志和业务日志的区别时提到过业务日志的关注点和系统日志有本质区别,业务日志关注于业务,而业务在面向对象的编程体系中往往表现为一个粗粒度的业务方法,正因为业务日志和系统日志的关注点的粒度不同,从而使AOP设计成为一种可能。

2.      业务日志框架的基本特性

一个完备的业务日志框架应该具备如下基本特性:

<o:p></o:p>

1.       业务日志记录、输出和查询(这是最基本的功能需求);

2.       所输出的业务日志应该从业务和操作两个维度进行分类,以支持更加灵活的日志分类检索;

3.       支持多线程:业务日志组件会在多线程环境中使用,需要确保线程安全性;

4.       稳定性:业务日志组件必须保持高度的稳定性,不能因为组件内部错误导致业务代码的崩溃;

5.       高性能:业务日志组件需要提供高速的日志记录功能以应对大请求流量下业务系统的正常运转;

<o:p></o:p>

以上的基本特性给框架的设计上也带来了一些约束和挑战:

<o:p></o:p>

1.       方便检索的业务需求限制了日志输出介质必须为数据库或是某种支持快速检索的存储媒介;

2.       为了满足稳定性和高性能的需求,可以采用异步消息来处理日志信息的输出,同时也会带来一系列的设计上的挑战;

3.       AOP要求框架的设计必须严格遵循OO的设计原则,以便于清晰地识别关注点和切入点;

4.       业务日志信息的复杂性增加了客户端调用代码的复杂程度,设计应尽可能封装复杂度,提供简单的外部接口,另外业务日志的记录被抽象到通用的日志记录切面,对于业务日志信息中的会话信息(如用户标识、客户端机器标识),需要用一种优雅的设计方法来避免客户端开发人员的手动编码获取;

3.      框架设计

业务日志框架可以分为业务日志记录组件、业务日志输出组件和业务日志查询组件三大块,业务日志记录组件负责管理业务日志记录器(Bnlog)和业务日志框架的初始化配置, Bnlog对象负责按照不同的业务类型(BusinessType)和操作类型(EventType)接收各种记录了业务日志信息的业务日志对象(BnlogItem),Bnlog对象获取需要记录的业务日志,然后将日志对象委托给业务日志输出组件进行处理;业务日志输出组件则负责管理业务日志输出器(Appender),并使用JMS对业务日志进行异步处理,将其输出到支持快速查询的存储介质;业务日志查询组件相对简单地负责从存储介质中查询业务日志。整个业务日志框架搭建在IOC容器之上,所有的对象都由IOC容器统一进行管理,系统结构如下图所示:业务日志框架结构图

<v:shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" filled="f" stroked="f" coordsize="21600,21600" o:spt="75"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" o:extrusionok="f" gradientshapeok="t"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype>

整个框架架构的主要职责类和接口的UML类图如下(UML不支持Annaotation,故省略了一个主要的Annaotation BusinessLog,后面会详细介绍)

业务日志框架UML类图

<o:p> </o:p>

 

从上面的UML类图中可以看出,每个组件都包含一个接口,这些接口定义了每个组件的协作通信方式,而将其实现隐藏起来,由IOC容器配置指定具体实现类,这样可以无需更改代码就可以达到改变系统行为的目的。第二部分将对每个组件的详细设计进行阐述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值