[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.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://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.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://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()方法。
演唱会立即就開始了,演唱歌曲为 你是我的眼泪
正在上演个人演唱会。演唱曲目为 你是我的眼泪
演唱曲目结束,谢谢大家... |
最新文章
- Step by step SQL Server 2012的安装
- android service被系统回收的解决方法
- 【转】solr+ajax智能拼音详解---solr跨域请求
- sass最佳实践
- caffe IDE 开发环境配置
- leetcode Generate Parentheses python
- 加深理解UIView,UIResponder,UIController
- UVa 757 - Gone Fishing
- Cloudera Manager安装_搭建CDH集群
- jQuery中$.each()方法的使用
- Auto Layout - BNR
- java获取上个星期第一天和最后一天
- No趴笨小分队
- 使用java启动mybatis generator
- asp.net——上传图片生成缩略图
- oracle数据库字符集和客户端字符集(2%)是不同的,字符集转化可能会造成不可预期的后果
- 初入py
- [转]java框架spring中的opensessioninview有什么作用
- poj 1028 Web Navigation
- BZOJ4327 JSOI2012玄武密码(AC自动机)
热门文章
- 国外物联网平台初探(五) ——Exosite Murano
- POJ 1654 乱搞题?
- Solr快速入门(一)
- RDS中的.frm和.ibd文件转换为sql文件
- mysql连接出现error node【1045】
- C++调用matlab编程
- box-shadow 阴影剖析
- Sublime Text 3 Build 3047 安装/插件安装/C编程环境配置
- 怎么用js或jq点击展开,出现隐藏的DIV,点击收起DIV又隐藏起来.
- BZOJ 1691 [Usaco2007 Dec]挑剔的美食家 multiset_排序_贪心