返回介绍

4.3.1 定义切面

发布于 2024-08-17 00:45:50 字数 3824 浏览 0 评论 0 收藏 0

如果一场演出没有观众的话,那不能称之为演出。对不对?从演出的角度来看,观众是非常重要的,但是对演出本身的功能来讲,它并不是核心,这是一个单独的关注点。因此,将观众定义为一个切面,并将其应用到演出上就是较为明智的做法。

程序清单4.1展现了Audience类,它定义了我们所需的一个切面。

程序清单4.1 Audience类:观看演出的切面

Audience类使用@AspectJ注解进行了标注。该注解表明Audience不仅仅是一个POJO,还是一个切面。Audience类中的方法都使用注解来定义切面的具体行为。

Audience有四个方法,定义了一个观众在观看演出时可能会做的事情。在演出之前,观众要就坐(takeSeats())并将手机调至静音状态(silenceCellPhones())。如果演出很精彩的话,观众应该会鼓掌喝彩(applause())。不过,如果演出没有达到观众预期的话,观众会要求退款(demandRefund())。

可以看到,这些方法都使用了通知注解来表明它们应该在什么时候调用。AspectJ提供了五个注解来定义通知,如表4.2所示。

表4.2 Spring使用AspectJ注解来声明通知方法

注  解

通  知

@After

通知方法会在目标方法返回或抛出异常后调用

@AfterReturning

通知方法会在目标方法返回后调用

@AfterThrowing

通知方法会在目标方法抛出异常后调用

@Around

通知方法会将目标方法封装起来

@Before

通知方法会在目标方法调用之前执行

Audience使用到了前面五个注解中的三个。takeSeats()和silence CellPhones()方法都用到了@Before注解,表明它们应该在演出开始之前调用。applause()方法使用了@AfterReturning注解,它会在演出成功返回后调用。demandRefund()方法上添加了@AfterThrowing注解,这表明它会在抛出异常以后执行。

你可能已经注意到了,所有的这些注解都给定了一个切点表达式作为它的值,同时,这四个方法的切点表达式都是相同的。其实,它们可以设置成不同的切点表达式,但是在这里,这个切点表达式就能满足所有通知方法的需求。让我们近距离看一下这个设置给通知注解的切点表达式,我们发现它会在Performance的perform()方法执行时触发。

相同的切点表达式我们重复了四遍,这可真不是什么光彩的事情。这样的重复让人感觉有些不对劲。如果我们只定义这个切点一次,然后每次需要的时候引用它,那么这会是一个很好的方案。

幸好,我们完全可以这样做:@Pointcut注解能够在一个@AspectJ切面内定义可重用的切点。接下来的程序清单4.2展现了新的Audience,现在它使用了@Pointcut。

程序清单4.2 通过@Pointcut注解声明频繁使用的切点表达式

在Audience中,performance()方法使用了@Pointcut注解。为@Pointcut注解设置的值是一个切点表达式,就像之前在通知注解上所设置的那样。通过在performance()方法上添加@Pointcut注解,我们实际上扩展了切点表达式语言,这样就可以在任何的切点表达式中使用performance()了,如果不这样做的话,你需要在这些地方使用那个更长的切点表达式。我们现在把所有通知注解中的长表达式都替换成了performance()。

performance()方法的实际内容并不重要,在这里它实际上应该是空的。其实该方法本身只是一个标识,供@Pointcut注解依附。

需要注意的是,除了注解和没有实际操作的performance()方法,Audience类依然是一个POJO。我们能够像使用其他的Java类那样调用它的方法,它的方法也能够独立地进行单元测试,这与其他的Java类并没有什么区别。Audience只是一个Java类,只不过它通过注解表明会作为切面使用而已。

像其他的Java类一样,它可以装配为Spring中的bean:

如果你就此止步的话,Audience只会是Spring容器中的一个bean。即便使用了AspectJ注解,但它并不会被视为切面,这些注解不会解析,也不会创建将其转换为切面的代理。

如果你使用JavaConfig的话,可以在配置类的类级别上通过使用EnableAspectJ-AutoProxy注解启用自动代理功能。程序清单4.3展现了如何在JavaConfig中启用自动代理。

程序清单4.3 在JavaConfig中启用AspectJ注解的自动代理

假如你在Spring中要使用XML来装配bean的话,那么需要使用Spring aop命名空间中的<aop:aspectj-autoproxy>元素。下面的XML配置展现了如何完成该功能。

程序清单4.4 在XML中,通过Spring的aop命名空间启用AspectJ自动代理

不管你是使用JavaConfig还是XML,AspectJ自动代理都会为使用@Aspect注解的bean创建一个代理,这个代理会围绕着所有该切面的切点所匹配的bean。在这种情况下,将会为Concertbean创建一个代理,Audience类中的通知方法将会在perform()调用前后执行。

我们需要记住的是,Spring的AspectJ自动代理仅仅使用@AspectJ作为创建切面的指导,切面依然是基于代理的。在本质上,它依然是Spring基于代理的切面。这一点非常重要,因为这意味着尽管使用的是@AspectJ注解,但我们仍然限于代理方法的调用。如果想利用AspectJ的所有能力,我们必须在运行时使用AspectJ并且不依赖Spring来创建基于代理的切面。

到现在为止,我们的切面在定义时,使用了不同的通知方法来实现前置通知和后置通知。但是表4.2还提到了另外的一种通知:环绕通知(around advice)。环绕通知与其他类型的通知有所不同,因此值得花点时间来介绍如何进行编写。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文