Spring AOP 面向切面的Spring
定义AOP术语
描述切面的常用术语有:
- 通知 (advice)
- 切点 (pointcut)
- 连接点 (joinpoint)
下图展示了这些概念是如何关联的
Spring 对AOP的支持
Spring提供了四种类型的Aop支持
- 基于代理的经典SpringAop
- 纯 POJO切面
- @AspectJ注解驱动的切面
- 注入式AcpectJ切面(适用于Spring各版本)
前三种,都是SpringAOP实现的变体,Spring AOP构建在动态代理的基础之上.因此Spring对Aop的支持局限于方法拦截.
Spring 在运行时通知对象
通过在代理类中包裹切面,Spring在运行期把切面织入到spring管理的bean中,如图,代理类风闸u那个了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean. 当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑.
需要注意的是:知道应用需要被代理的Bean时,spring才会创建代理对象.并且,Spring只支持方法级别的连接点.
编写切点
切点用于准确定位应该在什么地方应用切面的通知.同志和切点是切面的最基本元素.因此,了解如何编写切点非常重要.
关于Spring AOP的AspectJ切点,最重要的一点就是Spring仅支持AspectJ切点指示器(pointcutdesignator)的一个子集。 让我们回顾下,Spring是基于代理的,而某些切点表达式是与基于代理的AOP无关的。表4.1列出了Spring AOP所支持的AspectJ切点指示器。
在Spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常。
为了阐述Spring中的切面,我们需要一个主题来定义切面的切点.我们定义一个 Performance 接口:
package com.itguang.demo.aop; public interface Performance {
public void perform();
}
Performance 可以代表任何类型的现场表演,如舞台剧、电影或音乐会。假设我们想编写Performance的perform()方法触发的通知。 下图 展现了一个切点表达式,这个表达式能够设置当perform()方法执行时触发通知的调用。
我们使用 execution()指示器,选择proformance的perform()方法. 方法表达式以 * 开始,表明我们不关心方法的返回值类型.然后我们指定了全限定类名和方法名.对于方法参数列表,我们使用两个点号 (..) 表明切点要选择任意的 perform() 方法,无论方法的入参是什么
现在假设我们需要配置的切点仅匹配concert包.在此场景下,可以使用within()指示器来限制匹配.
请注意我们使用了 && 操作符把 execution()和within()指示器连接在一起形成 and 关系. 类似的,我们可以使用 || 操作符标识 or 关系,而使用 ! 操作符标识 not 操作. 因为“&”在XML中有特殊含义,所以在Spring的XML配置里面描述切点时,我们可以使用and 来代替“&&”。同样,or和not可以分别用来代替“||”和“!”。
定义切面
我们已经定义了 Performance接口,它是切面中切点的目标对象,现在让我们使用AspectJ注解来定义切面.
/**
* 观看演出的切面
*
* @author itguang
* @create 2017-11-06 16:24
**/
@Aspect
public class Audience { /**
* 手机静音
*/
@Before("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void silenceCellPhone(){
System.out.println("Silence Cell Phone");
} /**
* 就做
*/
@Before("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void takeSeats(){
System.out.println("Taking seats");
} /**
* 鼓掌
*/
@AfterReturning("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void applause(){
System.out.println("pa pa pa");
} /**
* 表演失败(异常),退款
*/
@AfterThrowing("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void demandRefund(){
System.out.println("Demanding a refund");
}
}
Audience 类使用了 @AspectJ 注解进行了标注.该注解表明 Audience不仅仅是一个 POJO,还是一个切面.Audience类中的方法都适用注解定义切面的具体行为.
Audience有四个方法,定义了一个观众在观看演出时可能会做的事情。在演出之前,观众要 就坐(takeSeats())并将手机调至静音状态(silenceCellPhones())。如果演出很精彩 的话,观众应该会鼓掌喝彩(applause())。不过,如果演出没有达到观众预期的话,观众会 要求退款(demandRefund())。
AspectJ提供了5个注解来定义通知
上面的代码 相同的切点表达式我们重复了四遍,这样的重复让人感觉有些不对劲。如果我们只定义这个切点一次,然后每次需要的时候引用它,那么这会是一个很好的方案。 幸好,我们完全可以这样做:@Pointcut注解能够在一个@AspectJ切面内定义可重用的切点.
/**
* 观看演出的切面
*
* @author itguang
* @create 2017-11-06 16:49
**/
@Aspect
public class Audience2 { @Pointcut("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void performance(){ } /**
* 手机静音
*/
@Before("performance()")
public void silenceCellPhone(){
System.out.println("Silence Cell Phone");
} /**
* 就做
*/
@Before("performance()")
public void takeSeats(){
System.out.println("Taking seats");
} /**
* 鼓掌
*/
@AfterReturning("performance()")
public void applause(){
System.out.println("pa pa pa");
} /**
* 表演失败(异常),退款
*/
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("Demanding a refund");
}
}
performance()方法的实际内容并不重要,在这里它实际上应该是空的。其实该方法本身只是一个标识,供@Pointcut注解依附。
需要注意的是,除了注解和没有实际操作的performance()方法,Audience类依然是一个 POJO。我们能够像使用其他的Java类那样调用它的方法,它的方法也能够独立地进行单元测 试,这与其他的Java类并没有什么区别。Audience只是一个Java类,只不过它通过注解表明 会作为切面使用而已。
像其他的Java类一样,它可以装配为Spring中的bean:
@Bean
public Audience2 audience2(){
return new Audience2();
}
如果你使用JavaConfig的话,可以在配置类的类级别上通过使用EnableAspectJAutoProxy注解启用自动代理功能。
/**
* AOP config
*
* @author itguang
* @create 2017-11-06 16:53
**/
@Configuration
@EnableAspectJAutoProxy
public class AOPConfig { @Bean
public Audience2 audience2(){
return new Audience2();
} }
不管你是使用JavaConfig还是XML,AspectJ自动代理都会为使用@Aspect注解的bean创建一个代理,这个代理会围绕着所有该切面的切点所匹配的bean。,Audience类中的通知方法将会在perform()调用前后执行。
创建环绕通知
环绕通知是最为强大的通知类型.他能够让你所编写的逻辑将被通知的方法完全包装起来.实际上就像在一个方法中同时编写前置通知和后置通知.
/**
* 使用环绕通知的Audience切面
*
* @author itguang
* @create 2017-11-06 17:03
**/
@Aspect
public class Audience3 { @Pointcut("execution(* com.itguang.demo.aop.Performance.perform(..))")
public void performance(){
} @Around("performance()")
public void watchPerformance(ProceedingJoinPoint jp){
try {
System.out.println("Silence Cell Phone");
System.out.println("Taking seats");
//将控制权交给被通知的方法,即调用被通知的方法
jp.proceed();
System.out.println("pa pa pa");
}catch (Throwable e){
System.out.println("Demanding a refund");
}
} }
在这里,@Around 注解表明 watchPerformance()方法将会作为 perdormance() 切点的环绕通知.
关于这个心得通知方法,你注意到的可能是 它接受ProceedingJoinPoint 作为参数.这个对象是必须要有的,因为你要在通知中通过它来调用被通知的方法.
需要注意的是,别忘记调用proceed()方法。如果不调这个方法的话,那么你的通知实际上 会阻塞对被通知方法的调用。有可能这就是你想要的效果,但更多的情况是你希望在某个点 上执行被通知的方法。
有意思的是,你可以不调用proceed()方法,从而阻塞对被通知方法的访问,与之类似,你也 可以在通知中对它进行多次调用。要这样做的一个场景就是实现重试逻辑,也就是在被通知 方法失败后,进行重复尝试。
处理通知中的参数
上图中需要关注的是切点表达式中的argus(trackNumber) 限定符. 它表示传递给 playTrack() 方法的 int类型的 参数也会传到通知中去. 参数的名称 trackNumber也与切点方法签名中的参数相匹配.
Spring AOP 面向切面的Spring的更多相关文章
- Spring使用笔记(四) 面向切面的Spring
面向切面的Spring 一.面向切面的概念 在软件开发中,散布于应用多处的功能被称为横切关注点(cross-cutting concern). 通常来讲这些横切关注带点从概念上来讲是与应用逻辑相分离的 ...
- Spring实战第四章学习笔记————面向切面的Spring
Spring实战第四章学习笔记----面向切面的Spring 什么是面向切面的编程 我们把影响应用多处的功能描述为横切关注点.比如安全就是一个横切关注点,应用中许多方法都会涉及安全规则.而切面可以帮我 ...
- 第04章-面向切面的Spring
1. 什么是面向切面编程 AOP是什么 切面帮助我们模块化横切关注点. 横切关注点可被描述为影响应用[多处的]功能.如安全,应用许多方法会涉及安全规则. 继承与委托是最常见的实现重用 通用功能 的面向 ...
- 五、面向切面的spring(1)
spring的依赖注入看完了,接下来是spring中与DI一并重要的AOP了,开始吧,GO. 在软件开发中,散布于应用中多处的功能被称为横切发关注点,通常来讲,这些横切关注点从概念上市与应用的业务逻辑 ...
- Spring学习(四)--面向切面的Spring
一.Spring--面向切面 在软件开发中,散布于应用中多处的功能被称为横切关注点(cross- cutting concern).通常来讲,这些横切关注点从概念上是与应用的业 务逻辑相分离的(但是往 ...
- 面向切面的Spring
在软件开发中,发布于应用中多处的功能被称为横切关注点.通常,这些横切关注点从概念上是与应用的业务逻辑相分离的(但往往直接嵌入到应用的业务逻辑之中).将横切关注点与业务逻辑相分离是AOP所要解决的. 一 ...
- Spring系列(四) 面向切面的Spring
除了IOC外, AOP是Spring的另一个核心. Spring利用AOP解决应用横切关注点(cross-cutting concern)与业务逻辑的分离, 目的是解耦合. 横切关注点是指散布于代码多 ...
- Spring学习笔记(三):面向切面的Spring
Spring之面向切面编程 一.理解何为面向切面编程 对于这个的理解,我觉得Spring实战中的例子讲得很明白: 假设我现在是一个小区用户,每个月小区都要收电费,这时候就会来人查看电表,算出来这个月电 ...
- 六、面向切面的spring(2)
这个是承接五的,这部分主要的内容是在XML中声明切面. 一.在XML中声明切面 让我们先看一下spring中的AOP配置元素有哪些: AOP配置元素 用途 <aop:advisor> 定义 ...
随机推荐
- Python连载10-os包函数(续)
一.os包(接连载9) 1.函数:system() (1)用法:运行系统shell命令 (2)格式:os.system(系统命令) (3)返回值:打开一个shell或终端界面 (4)注意:一般是用su ...
- 3015C语言_流程设计
第五章 流程设计 5.1 C语句概述 C语言的语句用来向计算机系统发出指令,一个实际的源程序通常包含若干语句,这些语句用来完成一定的操作任务. 1.其他类型语句 函数调用语句(由函数调用加一个分号构成 ...
- JVM检测&工具
前几篇篇文章介绍了介绍了JVM的参数设置并给出了一些生产环境的JVM参数配置参考方案.正如之前文章中提到的JVM参数的设置需要根据应用的特性来进行设置,每个参数的设置都需要对JVM进行长时间的监测,并 ...
- sentinel 集群流控原理
为什么需要集群流控呢?假设需要将某个API的总qps限制在100,机器数可能为50,这时很自然的想到使用一个专门的server来统计总的调用量,其他实例与该server通信来判断是否可以调用,这就是基 ...
- 【dateFormatSymbols】JAVA特殊日期格式转换
记录:特殊日期格式转换,如将yyyyMMdd转为01MAY2019 public static final String DATE_VIP_FORMAT = "yyyyMMdd"; ...
- 【设计模式】行为型11解释器模式(Interpreter Pattern)
解释器模式(Interpreter Pattern) 解释器模式应用场景比较小,也没有固定的DEMO,中心思想就是自定义解释器用来解释固定的对象. 定义:给定一个语言,定义它的文法表示,并定义一个 ...
- HDU 3065:病毒侵袭持续中(AC自动机)
http://acm.hdu.edu.cn/showproblem.php?pid=3065 题意:中文题意. 思路:直接插入然后用一个数组记录id和cnt,因为n只有1000,可以开一个数组判断第几 ...
- c++ 队列的基本应用
c++ 队列的基本应用 题目描述 现在去营业厅办理业务,都要先取号,再等待叫号.叫号系统有两种模式: 1.取号,取号时要输入自己的11位电话号码,号码按取号的顺序存在系统中: 2.叫号,叫号时会显示当 ...
- 把大象装进冰箱:HTTP传输大文件的方法
上次我们谈到了HTTP报文里的div,知道了HTTP可以传输很多种类的数据,不仅是文本,也能传输图片,音频和视频. 早期互联网上传输的基本上都是只有几k大小的文本和小图片,现在的情况则大有不同.网 ...
- 微信开发:微信js_sdk分享,使用场景,网页在微信app内部分享时的标题与描述,包括logo设置(一)
主要有下面几步.首先大家先分清楚 小程序的appid,appSecret 跟公众号的appid,appSecret是不一样的.因为这两个都能拿到token,且是不同的值. 准备开始: 1.准备好 公众 ...