[Spring实战系列](17)编写切点与声明切面
切点和通知是切面的最基本元素。
关于Spring AOP的AspectJ切点,最重要的一点是Spring仅支持AspectJ切点指示器的一个子集。
| 类型 | 说明 |
|---|---|
| arg() | 限制连接点匹配參数为指定类型的运行方法。 |
| @args() | 限制连接点匹配參数由指定注解标注的运行方法。 |
| execution() | 用于匹配的是连接点的运行方法。 |
| this() | 限制连接点匹配AOP代理的Bean引用为指定类型的类。 |
| target() | 限制连接点匹配目标对象为指定类型的类。 |
| @target() | 限制连接点匹配特定的运行对象,这些对象相应的类具备指定类型的注解。 |
| within() | 限制连接点匹配指定的类型。 |
| @within() | 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时。方法定义再由指定的注解所标注的类里)。 |
| @annotation | 限制匹配带有指定注解连接点。 |
|
仅仅有execution指示器是唯一的运行匹配。而其它的指示器都是用于限制匹配的。这说明execution指示器是我们在编写切点定义时最基本的指示器。在此基础上,我们使用其它指示器来限制所匹配的切点。 |
1. 编写切点
方法表达式以*号開始,标示了我们不关心返回值的类型。然后,我们指定了全限定类名和方法名。
对于方法參数列表。我们使用(..)标示切点选择随意的perform()方法,不管该方法的參数是什么。


2. 在XML中声明切面
| 类型 | 说明 |
|---|---|
| <aop:advisor> | 定义AOP通知器。 |
| <aop:after> | 定义AOP后置通知(无论被通知的方法是否运行成功) |
| <aop:after-returning> | 定义AOP after-returning通知。 |
| <aop:after-throwing> | 定义 AOP after-throwing 通知。 |
| <aop:around> | 定义 AOP 围绕通知。 |
| <aop:aspect> | 定义切面。 |
| <aop:aspectj-autoproxy> | 启用@AspectJ注解驱动的切面。 |
| <aop:before> | 定义 AOP前置通知。 |
| <aop:config> |
顶层的AOP配置元素。
大多数的<aop:*>元素必须包括在<aop:config>元素内。 |
| <aop:declare-parents> | 为被通知的对象引入额外的接口,并透明的实现。 |
| <aop:pointcut> | 定义切点。 |
package com.sjf.bean;/*** 观众类* @author sjf0115**/public class Audience {public void takeSeats(){System.out.println("the audience is taking their seats...");}public void applaud(){System.out.println("very good, clap clap clap...");}public void demandRefund(){System.out.println("very bad, We want our money back...");}}
<bean id = "audience" class = "com.sjf.bean.Audience"></bean>
2.1 前置声明和后置声明
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><bean id = "singer" class = "com.sjf.bean.Singer"></bean><bean id = "audience" class = "com.sjf.bean.Audience"></bean><aop:config proxy-target-class="true"><!-- 声明定义一个切面 --><aop:aspect ref = "audience"><!-- 表演之前 --><aop:before method="takeSeats" pointcut="execution(* com.sjf.bean.Singer.perform(..))"/><!-- 表演之后 --><aop:after-returning method="applaud" pointcut="execution(* com.sjf.bean.Singer.perform(..))"/><!-- 表演失败之后 --><aop:after-throwing method="demandRefund" pointcut="execution(* com.sjf.bean.Singer.perform(..))"/></aop:aspect></aop:config></beans>
这条规则有几种例外场景,可是把Bean声明为一个切面时,我们总是从<aop:config>元素開始配置。
ref元素引用了一个Bean(Audience),该Bean实现了切面的功能。ref元素应用的Bean提供了在切面上通知所调用的方法。
<aop:before>元素定义了匹配切点的方法运行之前调用前置通知方法,audience Bean 的takeSeats()方法。<aop:after-returning>元素定义了一个返回后(after-returning)通知,在切点所匹配的方法调用之后在运行applaud()方法。<aop:after-throwing>元素定义了抛出异常后通知,假设全部匹配的方法运行时抛出不论什么异常,都将调用demandRefund()方法。

这似乎违反了DRY(不要反复你自己)原则。
我们做一下改动,能够使用<aop:pointcut>元素定义一个命名切点。
<aop:config proxy-target-class="true"><!-- 声明定义一个切面 --><aop:aspect ref = "audience"><aop:pointcut id="singerPerfom" expression="execution(* com.sjf.bean.Singer.perform(..))" /><!-- 表演之前 --><aop:before method="takeSeats" pointcut-ref="singerPerfom"/><!-- 表演之后 --><aop:after-returning method="applaud" pointcut-ref="singerPerfom"/><!-- 表演失败之后 --><aop:after-throwing method="demandRefund" pointcut-ref="singerPerfom"/></aop:aspect></aop:config>
2.2 声明围绕通知
使用前置通知和后置通知实现该功能的唯一方式是:在前置通知中记录開始时间。并在某个后置通知中报告演出的时长。但这种话,我们必须在一个成员变量中保存開始时间。
因此我们能够使用围绕通知。仅仅需在一个方法中实现就可以。
public void PerformTime(ProceedingJoinPoint joinPoint){// 演出之前System.out.println("the audience is taking their seats...");try {long start = System.currentTimeMillis();// 运行演出操作joinPoint.proceed();long end = System.currentTimeMillis();// 演出成功System.out.println("very good, clap clap clap...");System.out.println("该演出共须要 "+(end - start) + " milliseconds");} catch (Throwable e) {// 演出失败System.out.println("very bad, We want our money back...");e.printStackTrace();}}
这个对象很重要。由于它能让我们在通知里调用被通知 的方法。假设希望把控制转给被通知的方法时,我们能够调用ProceedingJoinPoint的proceed()方法。假设忘记调用proceed()方法,通知将会阻止被通知方法的调用。我们还能够在通知里多次调用被通知方法。这样做的一个目的是实现重试逻辑,在被通知的方法运行失败时重复重试。
声明围绕通知与声明其它类型的通知并没有太大的差别,仅仅须要<aop:around>元素。
<aop:config proxy-target-class="true"><!-- 声明定义一个切面 --><aop:aspect ref = "audience"><aop:pointcut id="singerPerfom" expression="execution(* com.sjf.bean.Singer.perform(..))" /><!-- 声明围绕通知 --><aop:around method="performTime" pointcut-ref="singerPerfom"/></aop:aspect></aop:config>
|
the audience is taking their seats...
正在上演个人演唱会...
very good, clap clap clap...
该演出共须要 37 milliseconds |
2.3 为通知传递參数
可是有时候通知并非不过对方法进行简单包装,还须要校验传递给方法的參数值,这时候为通知传递參数就非常实用了。
package com.sjf.bean;/*** 歌手实体类* @author sjf0115**/public class Singer {public void perform(String songName) {System.out.println("正在上演个人演唱会,演唱曲目为 " + songName);}}
package com.sjf.bean;/*** 主办方实体类* @author sjf0115**/public class Organizers {public void BeforeSong(String songName){System.out.println("演唱会立即就開始了,演唱歌曲为 " + songName);}public void AfterSong(){System.out.println("演唱曲目结束。谢谢大家...");}}
<? xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><bean id = "singer" class = "com.sjf.bean.Singer"></bean><bean id = "Organizers" class = "com.sjf.bean.Organizers"></bean><aop:config><!-- 声明定义一个切面 --><aop:aspect ref = "Organizers"><aop:pointcut id="singerPerform" expression="execution(* com.sjf.bean.Singer.perform(String)) and args(song)" /><aop:pointcut id="singerPerform2" expression="execution(* com.sjf.bean.Singer.perform(..))" /><aop:before method="BeforeSong" pointcut-ref="singerPerform" arg-names="song"/><aop:after-returning method="AfterSong" pointcut-ref="singerPerform2"/></aop:aspect></aop:config></beans>
切点标示了Singer的perform()方法。指定了String參数。
然后在args參数中标示了song作为參数。相同,<aop:before>元素引用了切点中song參数,标示该參数必须传递给Organizers的BeforeSong()方法。

|
演唱会立即就開始了,演唱歌曲为 你是我的眼泪
正在上演个人演唱会。演唱曲目为 你是我的眼泪
演唱曲目结束,谢谢大家... |
[Spring实战系列](17)编写切点与声明切面的更多相关文章
- Spring实战系列
作者:arccosxy 转载请注明出处:http://www.cnblogs.com/arccosxy/ 稀里糊涂的做了2年的Java Web后端开发,很多东西连蒙带猜外加百度,也算是完成了几个重要 ...
- [Spring实战系列](19)Servlet不同版本号之间的差别
1. 2.3版本号 2.3版本号 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application ...
- Spring 实战4学习笔记(转)
http://blog.csdn.net/21aspnet/article/details/51386557 1.IOC装配Bean 参考[spring实战4 2.2],作者提倡无XML配置化. 1. ...
- 【Spring实战】Spring注解配置工作原理源码解析
一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ...
- 【转】【Spring实战】Spring注解配置工作原理源码解析
一.背景知识 在[Spring实战]Spring容器初始化完成后执行初始化数据方法一文中说要分析其实现原理,于是就从源码中寻找答案,看源码容易跑偏,因此应当有个主线,或者带着问题.目标去看,这样才能最 ...
- Spring Boot实战系列-----------邮件发送
快速导航 添加Maven依赖 配置文件增加邮箱相关配置 Service.Test项目代码构建 五种邮件发送类型讲解 文本邮件 html邮件 附件邮件 html内嵌图片邮件 模板邮件 问题汇总 添加ma ...
- Spring Boot实战系列(7)集成Consul配置中心
本篇主要介绍了 Spring Boot 如何与 Consul 进行集成,Consul 只是服务注册的一种实现,还有其它的例如 Zookeeper.Etcd 等,服务注册发现在微服务架构中扮演这一个重要 ...
- 【Spring实战】----开篇(包含系列目录链接)
[Spring实战]----开篇(包含系列目录链接) 置顶2016年11月10日 11:12:56 阅读数:3617 终于还是要对Spring进行解剖,接下来Spring实战篇系列会以应用了Sprin ...
- Spring实战(第4版).pdf - 百度云资源
http://www.supan.vip/spring%E5%AE%9E%E6%88%98 Spring实战(第4版).pdf 关于本书 Spring框架是以简化Java EE应用程序的开发为目标而创 ...
随机推荐
- vs2013+ffmpeg开发环境搭建【转】
本文转载自:http://blog.csdn.net/spaceyqy/article/details/43115391 每当看到配环境,我就泪流满面,好吧,闲话不多说,进入正题. 1.去官方下载ff ...
- Windows显示我的电脑到桌面以及给一些程序设置快捷键
Windows显示我的电脑到桌面,我测试的是windows server 2012和windows10 1.按Win(键盘上的微软徽标键)+R,输入: rundll32.exe shell32.dl ...
- Codeforces Round #438 (Div.1+Div.2) 总结
本来兴致勃勃的想乘着这一次上紫,于是很早很早的到了机房 但是好像并没有什么用,反而rating-=47 Codeforces Round #438(Div.1+Div.2) 今天就这样匆匆的总结一下, ...
- Super超级ERP系统---(7)货位管理
货位是ERP系统总的仓库管理中必不可少的,仓库是有货架组成,货架上的每个格子就是一个货位,所有货位上的商品的库存总和就是仓库商品的库存.仓库的货位主要分为货架和托盘,货架就是仓库的固定货位,托盘就是移 ...
- 2.Ventuz Designer常用工具介绍
Ventuz Designer常用工具介绍 1. 打开Ventuz Designer 图1.1 2. Ventuz Designer第一个界面 图2.1 Recent Projects:最近创建的 ...
- 使用Micrisoft.net设计方案 第二章组织模式
第二章组织模式 模式不仅依赖于它所包含的更小模式,同时也依赖包含它的更大的模式.它是描述复杂软件的系统方法. 本章的目标是让我们了解以下问题: 1.如何标识模式与模式的关系 2.如何把模式组织成模式集 ...
- 织梦dedecms红黑配图片模板源码v2.0
dedecms红黑配风格美女图片站是采用dedecms程序搭建的图片网站源码,网站感觉很大气,简约但是不简单,适合做图片网站.网站模板是收集其他网站的模板,感谢原网站提供者.在安装过程中出现问题,现已 ...
- 利用JavaScript制作简易日历
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <met ...
- Python 之 基础知识(二)
一.分支运算 在Python 2.x中判断不等于还可以用<> if语句进阶:elif if 条件1: ...... elif 条件2: ...... else: ...... 二.逻辑运算 ...
- hdu4009 Transfer water 最小树形图
每一户人家水的来源有两种打井和从别家接水,每户人家都可能向外输送水. 打井和接水两种的付出代价都接边.设一个超级源点,每家每户打井的代价就是从该点(0)到该户人家(1~n)的边的权值.接水有两种可能, ...