AOP原理及在架构设计中的应用
【关键词】AOP JavaEE 架构设计
1. AOP原理
1.1. AOP是什么
AOP(Aspect-Oriented Programming)就是面向方面的编程,这一概念最初由Xerox PARC研究中心提出。
AOP技术使得应用开发者仅仅关注于业务逻辑本身的开发,而不用纠缠于那些诸如安全、事务、日志等和业务逻辑无关但又是系统有效地执行业务逻辑所必须的通用性功能。AOP以“动态织入”的方式大大提高应用开发效率,有效地降低软件的复杂性,代码的清晰性、模块化、可测试性方面也会取得很好的提升。
1.2. AOP产品
经过多年的发展,目前Java领域的AOP实现有多种方案,主要包括:
1)AspectJ (TM): 创建于Xerox PARC. 有近十年历史,技术成熟。但其过于复杂;破坏封装;而且需要专门的Java编译器,易用性较差。
2)动态代理AOP:使用JDK提供的动态代理API或字节码Bytecode处理技术来实现。
基于动态代理API的具体项目有: JBoss 4.0 JBoss 4.0服务器
3)基于字节码的AOP,例如:
Aspectwerkz
CGlib,
Spring等。
1.3. AOP原理
1.3.1. 基本概念
AOP技术中将这些通用性功能称为方面(Aspect)或切面(Pointcut, Advicor)。 在JDK提供的动态代理AOP和CGLib等字节码的AOP中,方面通过拦截器(Interceptor)来实现。
具体解释就是,在对Java方法调用时,AOP机制能自动进行方法拦截,允许你在方法调用前,调用后,以及执行异常时添加特定的代码,来完成需要的功能。
例如:调用User类的sayHello方法的基本过程如下图:
public class User
{
} |
如果想在调用前打印一条日志,AOP下的做法是为User类添加一个日志拦截器(如下图所示),而原有User类的代码无需任何修改。
1.3.2. 方法拦截器
不同厂商提供的方法拦截器规格不同,但基本原理类似。CGLib提供的拦截器接口:MethodInterceptor,仅提供了一个intercept接口(AOPAppliance提供类似的invoke方法)。
public Object intercept (Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable; |
日志拦截器的开发者,可以实现该接口,对被拦截的方法,例如:sayHello进行处理,在方法实际执行前,打印日志。
public class LogInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("invoke method(Before) sayHello!"); //实际执行方法 return proxy.invokeSuper( obj , args); } } |
原方式下,user的调用方式为
User user = new User();
user.sayHello(“张三”);
但要让User的sayHello方法被记录日志, user的创建方式有所不同。在Spring下,提供了一种最为简化的创建方法,
User user = (User)beanFactory.getBean(beanName);
user.sayHello(“张三”);
其中beanName是在Spring配置文件中为User配置的bean的ID。
1.3.3. 细化的拦截器
Spring框架对AOP的方面进行了细化处理,将每一次的方法拦截细分为before,after,throwing(异常)三个过程,并定义了三个advice接口
MethodBeforeAdvice,
AfterReturningAdvice,
ThrowsAdvice,
拦截器开发者只需实现自己关注的阶段,上面的日志拦截器在Spring框架下可以如下实现:
public class LogAdvisor extends MethodBeforeAdvice { private static Log log = LogFactory.getLog(LogAdvisor.class); public void before(Method method, Object[] args, Object target) throws Throwable { if(log.isDebugEnabled()) log.debug("记录日志(前):" + target +", 方法:" + method.getName()); } |
1.3.4. 拦截器串
通常,系统关注的功能有很多,例如:日志,事务,缓存等等,因此,实际系统中,通常是多个拦截器同时工作,形成一个拦截器串,各自关注相应特定的功能。
拦截器串协同工作的基本方式为
1)串行执行,即几个拦截器,按顺序依次执行。
但在有些系统中还存在特殊需求:
2) 忽略执行
在某些情况下,例如:sayHello的参数是“Admin”时,不记录日志,只开启事务和缓存功能, 那么Log拦截器的日志记录功能需要被忽略。这种情况通常在LogAdvisor内部,对参数进行判断来实现。
public class LogAdvisor extends MethodBeforeAdvice { private static Log log = LogFactory.getLog(LogAdvisor.class); public void before(Method method, Object[] args, Object target) throws Throwable { if(“ Admin ”.equals(args[0])) if(log.isDebugEnabled()) log.debug("记录日志(前):" + target +", 方法:" + method.getName()); } |
3) 跳出执行
public class SecurityInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if(“ Admin ”.equals(args[0])) return “管理员,你好!”;//实际执行方法 else return proxy.invokeSuper( obj , args); } } |
在某些情况下,要求终止被拦截的方法的实际执行,不再继续执行下一拦截器,而直接返回特定的结果,例如:sayHello的参数是“Admin”时,让该方法返回固定的值“管理员,你好!”。
1.3.5. AOP适用的方面
由于AOP技术本身的插件式特点,采用这种机制进行系统设计和程序开发能够为软件带来极大的灵活性和扩展性。目前,运用AOP对系统进行功能扩展主要关注的方面是:
Transactions 事务,例如Spring就利用AOP提供了通用性的事务管理器。
Logging, 日志,还包括Tracing等;
Profiling and Monitoring 性能分析和监控。
Authentication 权限,包括鉴权,安全控制等;
Caching 缓存,
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
Performance optimization 性能优化
等等。
2. 架构设计中AOP的运用
2.1. 运用方式
架构采用了JavaEE规范中经典的三层架构:表示层、业务层、持久层,如下图所示:
与一般的JavaEE架构不同, 该架构通过Factory模式在各层之前进行搭桥,通过对应的Factory类来创建下层对象。
工厂机制运用了Spring AOP技术,上层对象在请求下层资源时,可以通过代理机制切入若干功能,使得可以灵活扩展系统功能,而又使各层着重关注本职核心功能。值得注意的是,表示层采用的是Struts2框架,而它本身就是基于AOP原理进行设计的。如下图所示:
由于运用了Spring AOP技术,方面(Aspect)的开发就变成拦截器(Spring称为Advisor)的开发。该架构将Spring AOP规范定义的before,after,throwing三个阶段,和CGLib定义的invoke阶段整合为了一个抽象类: AbstractAdvisor, 方便设计人员开发新的拦截器。
并且Spring通过AOP机制已经提供通用的事务(Transaction)控制,调试(Debug),类加载分析,并发控制,简单的性能监控等基础性功能。
2.2. AOP 应用举例
2.2.1. 基本功能
1. 业务日志(工单)
凡是基于数据库的系统,本质上都是对库表记录的增删改查。而从业务层面看,很多时候,用户需要对数据的操作留下痕迹,即业务日志,以便审计。
在公司项目的J2EE架构中设计了业务日志拦截器,并切入对BO的操作,完成对业务操作的记录。用户可以通过专门的界面对业务日志进行查询和分析。
工作原理
业务日志的基本数据格式为:
操作时间,来源IP,操作工号,操作状态,操作动作,操作类型,失败原因,数据
日志按操作类型分:增加,删除,修改(查询暂不记录), 操作成功,失败时都要记录。记录业务日志的主要依据是被拦截的对象和方法信息,。在执行方法本体后,即业务方法成功执行后,记录成功日志;在方法本体抛出异常时,记录失败日志。主要代码见下:
public class Bu sin essLogAdvisor extends AbstractAdvisor {
public Object invoke(MethodInvocation invocation) throws Throwable { //准备参数 Object result = null; Object object = invocation.getThis(); //被拦截的对象 Method method = invocation.getMethod(); //被拦截的方法 Object[] args = invocation.getArguments(); // 参数 //before, 之前必要的检查 …… try { result = invocation.proceed(); //以下执行记录日志的操作 doLog(object, method, args, target, Bu sin essLog.STATE_SUCCESS,null); }catch(Exception e) { //以下记录失败日志 doLog(object, method, args, target, Bu sin essLog.STATE_FAIL,failcause); } } |
其中doLog方法将信息保存到库表中。(出于性能考虑,可以采用异步方式保存业务日志到数据库)。
2. 性能监控
Spring本身提供了一个监控拦截器,但功能不是很完善。公司项目架构中设计了一套Monitor框架,其功能包含:性能监控(Profiling , Monitoring),访问分析(Analyzing)两个方面。
Monitor可切入表示层,业务层BO,持久层DAO三层。Monitor包括以下功能:
¨ 按安模块和功能分析性能指标
¨ 实时流量监控
¨ 按模块和功能分析流量
¨ 流量时间分布分析
¨ 访问错误分析
这些功能较为全面的为系统管理员提供的系统的各项运行指标,方便用户查找性能瓶颈,进行性能调优。
实现原理:
在方法拦截之前(before),执行后(after)进行时间记录,并取差值,得到该方法的执行时间(单位:秒)就是该方法的执行性能;再将其连同模块名,类名,方法名等信息存入数据库,就可以进行多项性能和流量分析功能。其中流量分析可以采用内存变量存储,而不是根据监控记录进行分析。
3. 其他功能
利用AOP原理,为架构带来的其他功能还包括:数据缓存,安全检查,服务路由等等,例如Struts2,开源服务总线CXF等就以AOP为基础架设其基本架构和功能。
总之,将AOP技术运用在架构设计中,将为银行,电信,证券等大型系统的功能扩展性,灵活性,易用性带来很大的提升。
【参考文献】
1. 《spring2.0-reference》(中文版)
2. 《什么是AOP?》,邓辉, http://blog.chinaunix.net/u/1163/showart.php?id=434692