面向切面的Spring
2015-12-07 21:53
316 查看
下班了,坐下来学习一会,单身狗狗回去也是无聊。昨天看了一下切面的知识,信息量有点多,脑子还是一片混 沌,就打算再看一遍,不过这次是边整理边看。
主要内容有:
软件开发过程中分布于应用中的多处的功能被称为横切关注点,这些关注点与应用的业务逻辑时相分离的,将这些横切关注点和业务逻辑想分离是面向切面编程要解决的。是不是有点晦涩,举个例子是怎么回事呢,比如我们火车票事业部做火车票的业务,其中有个功能是发送邮件,发送邮件这个功能跟火车票的业务逻辑是不相干的,可能其他部门也要发送邮件这个功能,那么发送邮件就是横切关注点,把发送邮件作为一个切面嵌入到火车票业务逻辑中,可以实现分离。是不是有点小明白了,继续。
- 通知:描述切面的作用和什么时候起作用,即什么、何时
- 切点:描述切面作用的范围,即何处
- 切面:通知和切点的集合,即什么、何时、何处
- 连接点:能够插入切面的地方
- 引入:为现有的类添加新方法或属性
- 织入:将切面应用到现有对象来创建代理的过程
那么Spring是如何利用AOP 的呢?是不是也有这个疑问?答案就是Spring的AOP框架 采用一个包裹目标对象的代理类来执行切面的的逻辑,搜噶!遗憾的是Spring只支持方法的连接点,(也就是只能在方法级别插入切面,不能再方法内部插入,书上说的没我说的明白)但是基本上已经够用了。
## Spring XML 编写切面 ##
Spring借助AspectJ的切点表达式语音来定义Spring切面,Spring支持的指示器有:
arg() 限制连接点匹配参数 为 指定类型的执行方法
@args() 限制连接点匹配参数 由 指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的Bean引用 为 指定的类型的类
target() 限制连接点匹配目标对象 为 指定类型的类
@target() 限制连接点匹配目标对象 为 特定的执行对象,这些对象要具备指定的类型的注解
within() 限制连接点匹配 指定的类型
@within() 限制连接点匹配 指定注解标注的类型
annotation 限制匹配 带有指定注解的连接点
举个编写切点的例子(切点是啥,看前面):
execution(com.springinaction.springidol.Instrument.play(…))&&within(com.springinaction.springidol. )
啥意思呢,就是当springidol包下的play()方法执行时,会触发通知,通知是啥,看前面。
其实还有一个bean()指示器,用Bean的ID来表示Bean。比如:
execution(*com.springinaction.springidol.Instrument.play(…)) and !bean(eddie)
啥意思,就是Bean的名字不是eddie的play()方法执行时,会触发通知,eddie的play()方法执行时不会触发通知,就这么简单。
一个POJO类声明为切面有两种方式,一种是在XML中,一种是使用@AspectJ注解。先看第一种。
语法:
定义AOP通知器
定义AOP后置通知
定义AOP after-returning通知
定义AOP after-throwing后置通知
定义AOP环绕通知
定义切面
启用@AspectJ 注解驱动的切面
定义AOP前置通知
顶层的AOP配置元素
为被通知的对象引入额外的借口
定义切点
看上去是不是有点晕,别担心,后面你就都会了。因为Example来了,例子一直让我很惊喜,因为例子的存在大大简化了我们的理解。
我们定义一个观众类:
然后XML把这个Bean引入
下面才是我们的核心,在XML中把这个POJO声明为一个切面。
或者采用简化的方式:
哼,还用得着解释么,是不是全明白了,继续加油↖(^ω^)↗。
声明环绕通知:
假如有个一个POJO
XML如下:
为通知传递一个参数:
加入一个切点有一个参数,那么怎么把这个参数传给通知呢?看下面:
歌曲东风破 传过去了,嘎嘎。
通过切面引入新功能:
假如为所有的performer 引入一个新功能:
怎么办呢?
解释一下,就是 Perfromer接口会实现Contestant接口,具体接口的实现方法是GraciousContestant
跟之前一样,XML中把audience 注入进来
最后要做的是让Spring把 audience应用为一个切面
这段声明会自动代理一些Bean ,这些Bean与使用@Aspect注解的Bean中用@Pointcut 注解的方法匹配
今天继续:
注解环绕通知,要使用@around注解
和之前相比,区别就是POJO使用@Around标注,省去了XML中的配置
主要内容有:
1. 什么是面向切面编程和AOP术语 2. Spring XML 编写切面 3. 使用@aspectJ 编写切面 ## 什么是面向切面编程和AOP术语 ##
软件开发过程中分布于应用中的多处的功能被称为横切关注点,这些关注点与应用的业务逻辑时相分离的,将这些横切关注点和业务逻辑想分离是面向切面编程要解决的。是不是有点晦涩,举个例子是怎么回事呢,比如我们火车票事业部做火车票的业务,其中有个功能是发送邮件,发送邮件这个功能跟火车票的业务逻辑是不相干的,可能其他部门也要发送邮件这个功能,那么发送邮件就是横切关注点,把发送邮件作为一个切面嵌入到火车票业务逻辑中,可以实现分离。是不是有点小明白了,继续。
AOP术语包括:
- 通知:描述切面的作用和什么时候起作用,即什么、何时
- 切点:描述切面作用的范围,即何处
- 切面:通知和切点的集合,即什么、何时、何处
- 连接点:能够插入切面的地方
- 引入:为现有的类添加新方法或属性
- 织入:将切面应用到现有对象来创建代理的过程
那么Spring是如何利用AOP 的呢?是不是也有这个疑问?答案就是Spring的AOP框架 采用一个包裹目标对象的代理类来执行切面的的逻辑,搜噶!遗憾的是Spring只支持方法的连接点,(也就是只能在方法级别插入切面,不能再方法内部插入,书上说的没我说的明白)但是基本上已经够用了。
## Spring XML 编写切面 ##
Spring借助AspectJ的切点表达式语音来定义Spring切面,Spring支持的指示器有:
arg() 限制连接点匹配参数 为 指定类型的执行方法
@args() 限制连接点匹配参数 由 指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的Bean引用 为 指定的类型的类
target() 限制连接点匹配目标对象 为 指定类型的类
@target() 限制连接点匹配目标对象 为 特定的执行对象,这些对象要具备指定的类型的注解
within() 限制连接点匹配 指定的类型
@within() 限制连接点匹配 指定注解标注的类型
annotation 限制匹配 带有指定注解的连接点
举个编写切点的例子(切点是啥,看前面):
execution(com.springinaction.springidol.Instrument.play(…))&&within(com.springinaction.springidol. )
啥意思呢,就是当springidol包下的play()方法执行时,会触发通知,通知是啥,看前面。
其实还有一个bean()指示器,用Bean的ID来表示Bean。比如:
execution(*com.springinaction.springidol.Instrument.play(…)) and !bean(eddie)
啥意思,就是Bean的名字不是eddie的play()方法执行时,会触发通知,eddie的play()方法执行时不会触发通知,就这么简单。
一个POJO类声明为切面有两种方式,一种是在XML中,一种是使用@AspectJ注解。先看第一种。
语法:
定义AOP通知器
定义AOP后置通知
定义AOP after-returning通知
定义AOP after-throwing后置通知
定义AOP环绕通知
定义切面
启用@AspectJ 注解驱动的切面
定义AOP前置通知
顶层的AOP配置元素
为被通知的对象引入额外的借口
定义切点
看上去是不是有点晕,别担心,后面你就都会了。因为Example来了,例子一直让我很惊喜,因为例子的存在大大简化了我们的理解。
我们定义一个观众类:
pacage com.springinaction.springidol; public calss Audience{ public void takeSeats(){ system.out.printlin("the audience is taking their seats.") } public void turnOffCellPhones(){ system.out.printlin("the audience is turning their cellphones.") } public void applaud(){ system.out.printlin("CLAP CLAP CLAP CLAP CLAP CLAP.") } public void demandRefund(){ system.out.printlin("Boo! we want our money back!") } }
然后XML把这个Bean引入
<bean id = "audience" class = "com.springinaction.springidol.Audience" />
下面才是我们的核心,在XML中把这个POJO声明为一个切面。
<aop:config> <aop:aspect ref = "audience"> <aop:before pointcut = "execution(*com.springinaction.springidol.performer.perform(...))" method = "takeSeats" /> <aop:before pointcut = "execution(*com.springinaction.springidol.performer.perform(...))" method = "turnOffCellPhones" /> <aop:after-returning pointcut = "execution(*com.springinaction.springidol.performer.perform(...))" method = "applaud" /> <aop:after-throwing pointcut = "execution(*com.springinaction.springidol.performer.perform(...))" method = "demandRefund" /> </aop:aspect> </aop:config>
或者采用简化的方式:
<aop:config> <aop:aspect ref = "audience"> <aop:pointcut id="performace" expression = "execution(*com.springinaction.springidol.performer.perform(...))" method = "takeSeats" /> <aop:before pointcut-ref ="performace" method = "takeSeats" /> <aop:before pointcut-ref ="performace" method = "turnOffCellPhones" /> <aop:after-returning pointcut-ref ="performace" method = "applaud" /> <aop:after-throwing pointcut-ref ="performace" method = "demandRefund" /> </aop:aspect> </aop:config>
哼,还用得着解释么,是不是全明白了,继续加油↖(^ω^)↗。
声明环绕通知:
假如有个一个POJO
public void watchperformance(ProceedingJiontPoint jointpoint){ try{ system.out.printlin("the audience is taking their seats."); system.out.printlin("the audience is turning their cellphones."); long start = Syetem.currentTimeMillis(); jointpoint.proceed(); long end = System.currentTimeMillis(); system.out.printlin("CLAP CLAP CLAP CLAP CLAP CLAP."); syetem.out.printlin("the perform took"+(end-start)+"milliseconds"); } catch (Throwable t){ system.out.printlin("Boo! we want our money back!"); }
XML如下:
<aop:config> <aop:aspect ref = "audience"> <aop:pointcut id="performace2" expression = "execution(*com.springinaction.springidol.performer.perform(...))" /> <aop:around pointcut-ref ="performace2" method = "watchPerformance()" /> </aop:aspect> </aop:config>
为通知传递一个参数:
加入一个切点有一个参数,那么怎么把这个参数传给通知呢?看下面:
<aop:config> <aop:aspect ref = "audience"> <aop:pointcut id="performace3" expression = "execution(*com.springinaction.springidol.performer.perform(string))" and args (dongfengpo) /> <aop:around pointcut-ref ="performace3" method = "watchPerformance" arg-names = "dongfengpo"/> </aop:aspect> </aop:config>
歌曲东风破 传过去了,嘎嘎。
通过切面引入新功能:
假如为所有的performer 引入一个新功能:
pacage com.springinaction.springidol; public interface Contestant{ void receiveAward(); }
怎么办呢?
<aop:config> <aop:aspect > <aop:declare-parents type-matching = "com.springinaction.springidol.Perfromer+" implent-interface ="pacage com.springinaction.springidol.Contestant" default-impl = "pacage com.springinaction.springidol.GraciousContestant" </aop:aspect> </aop:config>
解释一下,就是 Perfromer接口会实现Contestant接口,具体接口的实现方法是GraciousContestant
使用@aspectJ 编写切面
直接上代码,如何把前面的audience 使用注解声明为一个切面pacage com.springinaction.springidol; @Aspect public calss Audience{ @Pointcut("execution(*com.springinaction.springidol.performer.perform(...))") public void performance(){ } @Before(" performance()") public void takeSeats(){ system.out.printlin("the audience is taking their seats.") } @Before(" performance()") public void turnOffCellPhones(){ system.out.printlin("the audience is turning their cellphones.") } @AfterReturning(" performance()") public void applaud(){ system.out.printlin("CLAP CLAP CLAP CLAP CLAP CLAP.") } @AfterThrowing(" performance()") public void demandRefund(){ system.out.printlin("Boo! we want our money back!") } }
跟之前一样,XML中把audience 注入进来
<bean id = "audience" class = "com.springinaction.springidol.Audience" />
最后要做的是让Spring把 audience应用为一个切面
<aop:aspectj-autoproxy />
这段声明会自动代理一些Bean ,这些Bean与使用@Aspect注解的Bean中用@Pointcut 注解的方法匹配
今天继续:
注解环绕通知,要使用@around注解
@Around("performance()")
public void watchperformance(ProceedingJiontPoint jointpoint){ try{ system.out.printlin("the audience is taking their seats."); system.out.printlin("the audience is turning their cellphones."); long start = Syetem.currentTimeMillis(); jointpoint.proceed(); long end = System.currentTimeMillis(); system.out.printlin("CLAP CLAP CLAP CLAP CLAP CLAP."); syetem.out.printlin("the perform took"+(end-start)+"milliseconds"); } catch (Throwable t){ system.out.printlin("Boo! we want our money back!"); }
和之前相比,区别就是POJO使用@Around标注,省去了XML中的配置
相关文章推荐
- java基础知识巩固
- java学习:利用JScrollpane增加文本域滚轮(滚动条)
- Java运行时数据区
- Java笔记---Swing 编程中添加组件没有立即显示的问题
- Java 动态代理机制分析及扩展
- java排序算法
- java 程序性能优化《第二章》设计优化 2.1善用设计模式 1 单例模式
- Spring的生命周期及注入详解
- JavaEE_Mybatis_SpringMVC_框架整合_lesson3_框架整合+测试用例,数据库到前台的开发流程
- 欢迎使用CSDN-markdown编辑器
- Java三大框架
- Java [Leetcode 43]Multiply Strings
- 【java学习笔记s】设计模式--静态代理
- JavaSE-JPasswordField 中得到的字符数组转化为字符串(密码乱码问题)
- java 线程池介绍
- myeclipse下SVN文件标记无法显示
- Java String的split操作
- 【Java基础】Java多线程小结
- Java基础_03_Java数组
- spring-boot 测试