AOP(面向切面编程)
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是OOP的扩展和延伸,并不能取代OOP,AOP为OOP不能解决的问题提供了很好的方式。
例如,我们现在需要在持久层的某个save方法前面加一个权限校验的方法。
按照正常的想法,我们会在dao类上添加一个check权限的方法然后在调用save方法之前调用check方法,但是问题来了,当出现成千上百的保存方法的时候,我们就需要在成百上千的类中添加check校验方法,这样就很麻烦
使用纵向继承的方式,我们可以编写一个BaseDao类,这个类中我们编写一个check校验方法,当我们某各类需要加入权限校验方法的时候,我们只需要继承BaseDao类并调用BaseDao类中的check方法就行了。但是,使用继承的方式虽然说比上面的方法好一些,但是也并不尽人意,比如当我们这个权限校验方法不需要的时候,我们必须删除这些extends和子类调用BaseDao的check方法。AOP为我们解决这类问题提供了很好的方案。
AOP(横向抽取),其实AOP的原理就是使用了Java中的代理模式,具体可以参考这篇文章。这时候我们在把save方法抽取出来,我们使用Proxy模式增强save方法。
AOP的好处和Spring AOP底层实现
对程序进行曾倩,不修改源码的情况下,AOP可以进行权限校验,日志记录,性能监控,事务控制等功能。
Spring AOP底层使用动态代理模式,在被代理类实现某种接口的时候使用JDK动态代理,在被代理类没有实现某个接口的时候使用cglib动态代理。
AOP相关术语
首先我们先列出需要实现AOP的代码类1
2
3
4
5
6public class UserDao{
public void save(){}
public void find(){}
public void update(){}
public void delete(){}
}
我们对照上面代码看
JoinPoint:连接点,可以被拦截到的点。这里四个crud方法都是可以进行方法增强的,所以这四个方法都可以被称为JoinPoint
PointCut:切入点,真正被拦截的点,如果这四个方法中我们只对save方法进行了增强,那么save方法就是PointCut。
Advice:通知增强,假如我们现在对save方法进行权限校验,那么这个check方法就称为通知或者增强,而且这是方法层面的增强
Introduction:引介,类方面的增强
Target:被增强的对象,如果现在我们对UserDao这个类增强,那么UserDao就是Target
Waving:织入,它是一个过程,指的是我们将通知(Advice)应用到目标(Target)过程,将全县校验的方法的代码应用到UserDao的save方法上的过程。
Proxy:代理对象,一个类被AOP织入增强之后就产生了一个结果代理类
Aspect:切面,是切入点和通知的结合。
Spring AOP的入门开发
AOP的配置
1 | <aop:config> |
通知的类型
前置通知 目标方法执行前进行操作(权限校验..)
1
<aop:before method="xxx" pointcut-ref="xxx">
后置通知 目标方法执行之后进行操作(日志..),可以获得被增强方法返回值
1
2<aop:after-returning method="xxx" pointcut-ref="xxx" returning="returning对应的名字">
<!--后置增强方法里面传入 Object 与returning对应的名字-->环绕通知 目标方法执行之后之前进行操作,可以控制方法是否执行
1 | <aop:round method="around" pointcut-ref="切入点"> |
1 | //环绕增强方法实例 |
- 异常抛出通知 抛出异常的时候进行的操作(事物回滚),可以获取异常信息
1
<aop:after-throwing method="afterThrowing" pointcut-ref="切入点" throwing="给异常取个名字">
1 | //增强方法 |
- 最终通知 类似于finally,不管有没有异常都会执行的操作
1
<aop:after method="xxx" pointcut-ref="xxx">
切入点表达式
基于execution的函数完成
语法
[访问修饰符] 方法返回值 包名.类名.方法名(参数)
execution( 方法修饰符 方法返回值 方法所属类 匹配方法名 ( 方法中的形参表 ) 方法申明抛出的异常 )
public void com.lgq.UserDao.save(..) 两个点代表任意参数
public void com.lgq.UserDao.save(*,Integer)
“*”:代表一个任意类型的参数
public void com.lgq.UserDao.save(); ()匹配一个无参方法
具体还有

使用注解进行AOP开发
- 使用注解开发上面的XML配置的代码
1 | /** |