概念
AOP Aspect Oritened Programming 被称为面向切面编程。
OOP Object Oritened Programming 被称为面向对象编程。
面向对象编程侧重点为对象;面向切面编程侧重点为切面。
在大量组件中寻找时间、地点、逻辑相同的层面。比如Dao所有方法前开启事务、Controller所有方法后xxxx。
面向切面编程是以面向对象编程为基础,考虑将共通业务处理进行隔离,独立封装,之后通过SpringAOP配置方式作用。
AOP优点:将传统业务和共通业务代码进行解耦。例如事务控制、权限控制、日志记录等。
1. 切面组件(Aspect Bean)
封装共通处理的组件,将来会通过配置动态作用到其他业务组件方法上的功能。(要追加什么功能?)
2. 切入点(pointcut)
用于指定哪些业务组件方法追加切面组件功能。Spring提供了多种切入点表达式,例如方法表达式、类型表达式、组件名称表达式等。(给谁加功能?)
- 方法表达式
execution(修饰符? 返回类型 方法名(参数) 抛出异常?)
//匹配容器中所有bean中find开头的方法
execution(* find*(..))
//匹配DeptSerive组件中find开头的方法
execution(* cn.xdl.service.DeptSerive.find*(..))
//匹配cn.xdl.service包中所有类所有方法
execution(* cn.xdl.service.*.*(..))
//匹配cn.xdl.service包及子包中所有类所有方法
execution(* cn.xdl.service..*.*(..))
- 类型表达式
within(包名.类名)
//匹配DeptService组件所有方法
within(cn.xdl.service.DeptService)
//匹配cn.xdl.service包中所有类所有方法
within(cn.xdl.service.*)
//匹配cn.xdl.service包及子包中所有类所有方法
within(cn.xdl.service..*)
- bean名称表达式
bean(bean名字)
//匹配id=deptService的bean对象的所有方法
bean(deptService)
//匹配id以Service结尾的bean对象所有方法
bean(*Service)
- 通知(Advice)
用于指定业务组件和切面组件作用的时机。例如业务组件方法前、方法后、异常发生后等类型。(什么时候加?)
Spring框架提供以下几种通知:
- 前置通知 : 在目标方法前加切面功能
- 后置通知 : 在目标方法后加切面功能(目标方法正常结束)
- 最终通知 : 在目标方法后加切面功能(目标方法正常或不正常结束)
- 异常通知 : 在目标方法抛出异常后加切面功能
- 环绕通知 : 在目标方法前和后加切面功能
- 其他封装后的通知(例如事务等)
try{
//前置通知执行时机
//执行目标方法
//后置通知执行时机
}catch(){
//异常通知执行时机
}finally{
//最终通知执行时机
}
不同类型通知,对应切面组件的方法定义格式:
public void xxx(); //前置
public void xxx(参数); //后置
public void xxx(); //最终
public void xxx(Exception ex);//异常
public Object xxx(PrceedingJoinPoint pjp);//环绕
4. 目标组件(Target)
要被追加切面组件功能的组件。即:切入点指定的组件。
5. 动态代理(AutoProxy)
Spring AOP实现原理是采用动态代理技术完成的。Spring框架提供了两种生成代理对象的技术,分别是JDK Proxy API和CGLIB技术。
默认情况下有接口的目标组件采用JDK Proxy生成;没有接口的会采用CGLIB技术生成。
CGLIB技术原理:根据现有组件动态创建一个子类组件,然后将父类所有方法进行重写,在重写方法时可以调用父类功能和切面追加功能。
public class EmpServiceImpl$$EnhancerBySpringCGLIB$$55949fc7 extends EmpServiceImpl{
public void add() {
super.add();//调用父类add方法
loggerBean.mylog();//调用切面功能
}
public void findAll() {
super.findAll();//调用父类findAll方法
loggerBean.mylog();//调用切面功能
}
}
JDK Proxy API技术原理:根据现有组件接口动态创建一个代理组件。然后将接口方法进行实现,在方法中可以调用父类功能和切面追加功能。
public class $Proxy6 implements DeptService{
public void add() {
DeptServiceImpl.add();//调用组件方法
loggerBean.mylog();//调用切面功能
}
}
提示:可以在aop配置时,强制指定cglib技术生成子类代理对象。
<aop:config proxy-target-class="true">