1 AOP的简介
AOP最早是由AOP联盟的组织提出的一种思想,而Spring是AOP实现的最好的一个框架,并不是AOP是Spring创造出来的。
Spring最早的AOP是有自己的实现方式,但是非常繁琐,后来吸收了一个AOP开源框架AspectJ作为自身AOP的开发。
Spring的AOP开发有两套开发方式
- Spring的传统方式(非常繁琐,被弃用了)
- Spring基于AspectJ的AOP开发(正在使用)
为什么要AOP:(1)赖,一次开发,多次可用(如日志记录、事务管理等功能的实现)(2)为了更清晰的逻辑,可以让你的业务逻辑去关注自己本身的业务,而不去想一些其他的事情,这些其他的事情包括:安全,事物,日志等。
2 AOP的术语
- 通知(Advice)
就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,然后在想用的地方用一下。(方法层面的增强)
2.连接点(JoinPoint)
可以被拦截到的点:这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。
3.切入点(Pointcut)
真正被拦截到的点:上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用的过程叫织入,后面再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
4.切面(Aspect)
切面=多个通知+切入点。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。(现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切入点,搞出来的,明白这个概念就行了)
5.引入(introduction)
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。(类层面的增强)
6.目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。
7.织入(weaving)
把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时。(为什么是运行时,上一篇文章springAOP的实现原理有解释)
8.代理(proxy)
切面应用到目标对象来创建的新的代理对象。怎么实现整套aop机制的,都是通过代理。
3 AOP的XML开发
从上面的术语介绍来看,要想做AOP开发得有三步
* 有目标(target)和切入点(Pointcut)
* 有通知(Advice)
* 将通知织入(weaving)目标中的切入点得到切面(Aspect)
第一步: 编写目标和切入点
我们以一个UserDaoImpl类为例,实现将简单的增删查改
第二步:编写容纳通知的切面类及通知
第三步:配置XML文件进行织入
4 通知的类型
4.1 前置通知:在方法前通知
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
4.2 后置通知:在方法后通知
注:可以获得方法的返回值,但是returning的值必须和通知的入参Object是一样的(样例中为result)
<aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
4.3 环绕通知
注:可以控制原方法是否执行
<aop:around method="around" pointcut-ref="pointcut3" />
4.4 异常抛出通知
注:可以获得异常信息,但通知的入参必须为Throwable类,且名字和配置的throwing相同(样例中为ex)
<aop:after-throwing method="afterException" pointcut-ref="pointcut4" throwing="ex"/>
4.5 最终通知:等同于finally
<aop:after method="after" pointcut-ref="pointcut4"/>
4.6 引介通知(不用会)
applicationContext.xml
MyAspectXML.java
5 切入点表达式语法
- 基于execution的函数完成
- 语法
- [访问修饰符] 方法返回值 包名.类名.方法名(参数)
- 样例:public void com.hy.spring.CustomerDao.save(..)
- * com.hy.spring.CustomerDao.*(..) :任意地方都可以使用 * 代表通用
- *.com.hy.spring.CustomerDao+.save(..):+代表该类及其子类
- * com.hy.spring..*.*(..):两个点代表该包及其子包
6 AOP的注解开发
在aop的xml方式开发中,我们将开发步骤分为了三步:
* 有目标(target)和切入点(Pointcut)
* 有通知(Advice)
* 将通知织入(weaving)目标中的切入点得到切面(Aspect)
同样的,在aop的注解开发时,我们同样分为这三步
第一步:编写目标和切入点
这里我们用直接用一个CustomerDao作为目标实现。
第二步:编写通知
这里我们在一个名为MyAspectAnno的切面类中编写前置、后置、异常抛出等等通知。(后面会贴出具体实现)
第三步:配置切面类,进行织入
如下图,我们通过注解,配置了切面类、切入点、各种通知以及切入点和通知之间的联系