AOP的应用场景(异常处理、安全检查和缓存)

18 篇文章 0 订阅

本文内容摘自于王福强的《Spring揭秘》第11章,这是我见过的最好的一本讲解Spring背后原理、设计思想的书籍,虽然讲解的Spring版本有点老,但是基本上不影响Spring的学习。

一.异常处理

       或许你已经在使用AOP的方式进行异常处理,但是可能不知道这实际上对应着一个很有趣的术语,叫做Fault Barrier。同样地,在接触这个术语之前,我实际上已经将这个概念所阐述的理念应用于工作中,直到看到dev2dev网站上的一篇文章"Effective Java Exception",才知道原来这种异常的处理方式还对应这么一个有趣的术语。不过,在讲述Fault Barrier之前,我们有必要先来回顾一下Java中异常处理的相关内容。

1. Java异常处理

       异常处理是个很大的话题,限于篇幅,我们不可能详细讲述异常处理的方方面面。下面知识简单地回顾一下Java中的异常类型和对应的处理方式,以便引出Fault Barrier的概念。
       Java不是最早也不是唯一使用异常机制的语言。不过,Java却在引入Checked Exception的基础上为其自身的异常处理添加了少许的新意。我们先来看一下Java中的异常层次体系大体上是一种什么样的结构,如果11-1所示。
在这里插入图片描述
       在图11-1中,我们将Java中的异常类型分为如下两类:

  • 通常将java.lang.Error和java.lang.RuntimeException及其子类称之为unchecked exception。之所以如此称呼,是因为编译器不会对这些类型的异常进行编译器检查。因为java.lang.Error我们通常关心不着,所以,狭义上将java.lang.RuntimeException及其子类暂且称为unchecked exception也是可以的。
  • java.lang.Exception及其子类,但除去java.lang.RuntimeException分支,统称为checked exception。一旦在程序的方法定义中声明了将会抛出"checked exception",调用程序就必须对这些异常进行处理,而且编译器会在编译期间对这些异常类型进行检查。

       各位大师级任务对checked exception和unchecked exception的论战暂且放在一边,我们主要讲述一下二者具体的应用场景。

  • unchecked exception通常对应系统中的严重异常情况,这些情况应用程序一般无法恢复,比如数据库挂掉、网线连接中断、服务器崩溃等。所以unchecked exception所提供的信息一般不是为应用程序准备的,而是为人准备的,确切地说,是为了能够让系统维护人员能够根据所提供的信息来判定到底哪里出了问题,以便人工干预。
  • checked exception引入Java后,一直是备受争议。不过,我觉得这与概念本身没有任何关系,是否被应用于合适的场合是由人来决定的,而不是概念本身。checked exception通常用于表明系统中的某些罕见的非正常状态。对于一个业务方法来说,使用错误号(Error Code)的时代是通过返回-1之类的数字表明一些非正常状态,现在可以通过抛出不同类型的checked exception来表明这些非正常状态,并要求调用方对这些非正常状态进行处理,而编译器对checked exception的检查可以进一步加强这种契约关系。通常checked exception是可恢复的,也是意料之中的,它所提供的信息是面向应用程序的,应用程序可以根据系统逻辑对不同的checked exception类型进行有针对性的处理。

       在技术文章"Effective Java Exception"中,作者将unchecked exception对应的情况称之为Fault,而将checked exception对应的情况称之为Contingency。而Fault Barrier要处理的,就是对应Fault的情况,即unchecked exception。

2.Fault Barrier

       对于checked exception来说,不同的类型可以有不同的处理方式,这完全是由系统逻辑来决定的,调用方可以根据不同的类型,有针对性地对checked exception进行处理。反过来,对于unchecked exception来说,不同的类型则是没有太多必要的,因为不管你的应用程序抛出何种类型的unchecked exception,最终都是需要人工来进行干预,只要unchecked exception能够提供足够的信息,相应人员就可以进行处理,几乎就是无差别对待
       当系统中多个地方都可能抛出unchecked exception的时候,在引入Fault Barrier概念之前,我们可能会在每个调用的最顶层,分别添加异常处理逻辑对其进行处理。而就像前面所说的那样,unchecked exception实际上可以做的事情很少,通常就是记录日志、通知相应人员。所以,这些相同的逻辑实现可以归并于一处进行处理,而不是让他们分散到系统的各处,也就是说,对于系统中的Fault来说,它实际上就是一种横切关注点(corss-cutting concern)。
       鉴于此,我们完全可以实现一个对应Fault处理的Aspect,让其对系统中的所有可能的Fault情况进行统一的处理。这个专职于处理Fault的Aspect,我们就称之为Fault Barrier。
       实际上,我们从讲解Spring AOP的ThrowsAdvice开始,就提供了一个Fault Barrier的实现实例。在该实例中,我们通过电子邮件的方式将系统中的Fault情况,也就是以unchecked exception形式给出的信息转发给相关人员,并记录到日志。当然,如果可能,你还可以加入更多的处理,比如分析unchecked exception信息、为相关人员提供更加友好的系统信息等。

二.安全检查

       如果你已经使用Java开发Web应用程序多年,那么一定不会对Filter感到陌生吧?javax.servlet.Filter是Servlet规范为我们提供的一种AOP支持,通过它,我们可以为基于Servlet的Web应用添加相应的资源访问控制(当然,还可以做很多其他事情)。不过,基于Filter的Web应用的资源访问控制,仅仅是特定领域的安全检查需求。实际上,通过AOP,我们可以为任何类型的应用添加相应的安全支持。
       在介绍AOP概念的时候就曾经提到过,安全检查属于系统的一种横切关注点,按照原先的方法进行系统开发,势必让这些安全检查逻辑散落到系统各处,所以,对付它的最好办法就是用AOP。在将系统中可能需要安全检查的点排查清楚之后,我们就可以为这些点织入安全检查的逻辑了。
       要为系统中某个点添加安全支持,最简单的办法就是提供一个拦截器,对所有访问该店的调用进行拦截。所以,对于基本的安全检查的Aspect实现来说,如代码清单所示:

@Aspect
public class SecurityAspect{
	@Around("...")
	public Object doCheck(ProceedingJoinPoint pjp) throws Throwable{
		if(isIllegalRequest(pjp)){
			thorw new SecurityCheckingException("necessary information");
		}
		return pjp.proceed();
	}
}

       既然我们崇尚“不重新发明轮子”,在动手之前,有必要搜索一下是否有现成的,免去人力物力的浪费。
       实际上,作为基于Spring平台的一套安全框架,Acegi框架(也就是Spring Security)已经可以说在企业级应用的安全领域声名远扬了。它在Spring基础上,提供了完备的系统认证、授权、访问控制等安全检查功能。

三.缓存

       AOP应用的另一个主要场景是为系统透明地添加缓存支持。缓存可以在很大程度上提升系统的性能,但它不是业务需求,而是系统需求。在现有方法论的基础上为系统添加缓存支持,就会因为系统中缓存需求的广泛分布,造成实现上的代码散落。
       为了避免需要添加的缓存实现逻辑影响业务逻辑的实现,我们可以让缓存的实现独立于业务对象的实现之外,将系统中的缓存需求通过AOP的Aspect进行封装,只在系统中某个点确切需要缓存支持的情况下才为其织入。
       使用AOP为系统添加缓存很简单,如代码清单所示(代码示例没有添加同步逻辑,在生产环境下实现类似功能的时候需要考虑到这一点):

@Apsect
public class CachingAspect{
	private static Map cache = new LRUMap(5);

	public Object doCache(ProceedingJoinPoint pjp,Object key)throws Throwable{
		if(cache.containsKey(key)){
			return cache.get(key);
		}else{
			Object retValue = pjp.proceed();
			cache.put(key,retValue);
			return retValue;
		}
	}
}

       在没有使用AOP之前,要为系统某个地方加入缓存的话,恐怕也是以差不多的逻辑实现的。
       不过,现在不需要这么做了,原因如下:

  • 现在已经有许多现成的Caching产品实现,如EhCache、JBossCache等。
  • Spring Modules项目提供了对现有Caching产品的集成,这样就可以通过外部声明的方式为系统中的Joinpoint添加Caching支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值