一、前言
Spring提供了两个核心功能,一个是IoC(控制反转),另外一个便是AOP(面向切面编程),IoC有助于层与层之间纵向依赖的解耦,AOP则可以实现横向依赖之间的解耦。本文着重来讲面向切面编程的概念解析,实现原理以及应用实例。
二、基本概念
1、定义
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种纵向的对象层次关系结构。但OOP并不适合定义横向的关系,例如日志功能。代码往往横向地散布在所有对象层次中,而它又体现出与核心业务代码的无关性,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,权限认证、日志、事务等则是横切关注点。如果我们将横切关注点从业务逻辑代码中划分出来,并封装成为可重用模块。并在运行时,再动态地将横切关注点织入到核心关注点的指定方法、指定位置上。这样则便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
![image](https://i-blog.csdnimg.cn/blog_migrate/eaef9e4d32438091d6ea4d3394fc6253.jpeg)
2、AOP术语
- 增强(Advice)
也就是上面说的日志、性能、安全、事务、异常等横切逻辑功能,是由 aspect 添加到特定的 join point (即满足point cut 规则的 join point) 的一段代码。
增强的五种类型:
Before:前置增强,在方法被调用之前调用;
After:后置增强,在方法完成后调用增强,无论方法是否执行成功;
After-returning:后置成功增强,在方法成功执行之后调用增强;
After-throwing:后置异常增强,在方法抛出异常后调用增强;
Around:环绕增强,在方法调用前后分别调用增强。
- 连接点(Joinpoint)
程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。
- 切点(Pointcut)
在众多连接点中,选择使用增强的位置(通过execution(* com.lapland.demo..*(..)) 切入点表达式筛选)叫做切点。
切入点表达式:
关键字:execution(表达式)
表达式语法:
[访问修饰符] 返回值 包名.类名.方法名(参数列表)
全匹配方式:
execution(public void cn.itcast.service.impl.UserServiceImpl.saveUser())
访问修饰符可以不写:
execution(void cn.itcast.service.impl.UserServiceImpl.saveUser())
返回值可以使用通配符:通配符*
execution(* cn.itcast.service.impl.UserServiceImpl.saveUser())
包名可以使用通配符:当使用通配符时,有几级包,写几个*
execution(* *.*.*.*.UserServiceImpl.saveUser())
包名称可以使用..,表明的是当前包及其子包
execution(* cn..UserServiceImpl.saveUser())
类名可以使用通配符:
execution(* cn..*.saveUser())
方法名可以使用通配符:
execution(* cn..*.*())
参数列表可以指定类型:注意的是,如果是基本类型直接写类型名称,如果是引用类型,需要些包名.类名。lang也必须写。例如:java.lang.String
execution(* *..*.*(int))
参数列表可以使用通配符:注意:不能表示有无参数均可。只能表示参数的数据类型是任意的
execution(* *..*.*(*))
有无参数均可,可以使用..来表示:
execution(* *..*.*(..))
最简版:
execution(* *..*.*(..))
建议的写法:
切到业务层具体实现类即可:
execution(* cn.itcast.service.impl.*.*(..))