Spring AOP
(一) Spring AOP 概述
1 AOP是什么?
AOP 是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善。实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少模块,一个模块有哪些对象,对象有哪些属性),面向切面中包含一个一个动态过程(在对象运行时动态织入一些功能。)
2 AOP要解决什么问题?
实际项目中通常会将系统两大部分:核心关注点和非核心关注点
思考?
编程过程中首先要完成的是什么?核心关注点(核心业务)
非核心关注点如何切入到系统中?硬编码(违背OCP),AOP(推荐)
AOP就是要在基于OCP(开闭原则)在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以控制对象的执行。
3AOP实际项目应用场景?
AOP 通常应用于日志的处理,事务处理,权限处理,缓存处理等等。
4 AOP底层原理实现分析?
AOP底层基于代理机制实现功能扩展:(了解)
1) 假如目标对象(被代理对象)实现接口,则底层默认采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口)
2) 假如目标对象(被代理对象)没有实现接口,则底层默认采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型)。
5 AOP 相关术语
切面(aspect): 横切面对象,一般为一个具体类对象(可以借助@Aspect声明)
连接点(joinpoint):程序执行过程中某个特定的点,一般指被拦截到的的方法
切入点(pointcut):对连接点拦截内容的一种定义,一般可以理解为多个连接点的结合.
通知(Advice):在切面的某个特定连接点上执行的动作(扩展功能),例如around,before,after等
@Aspect 注解用于标识此类为一个AOP横切面对象
@Pointcut 注解用于定义本类中的切入点,本案例中切入点表达式用的是bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的id。
@Before 用于定义一个前置通知(满足切入点表达式的核心业务方法执行之前要执行的一个操作)
@After 用于定义一个后置通知(满足切入点表达式的核心业务方法执行之后要执行的一个操作)
术语增强:
切面:用于封装扩展业务的一个类的对象。
通知:切面扩展业务中的一个操作(方法)。
(二) AOP 基本步骤
step1:创建maven java 项目
step2:添加aop依赖
step3:配置aop 核心(基于xml,基于注解)
step4:定义核心业务(核心关注点):推荐先写接口再写实现类
step5:定义扩展业务(非核心关注点)
step6:基于配置实现非核心业务的切入
step7:编写测试类进行单元测试
(三)Spring AOP 编程增强
3.1 切面表达式增强
Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义
3.1-1 Bean表达式应用增强
3.1-2Within表达式应用增强
3.1-3 Execution表达式应用增强
3.1-4@annotation表达式应用增强
3.2 切面通知增强
在AOP编程中有五种类型的通知:
1) 前置通知 (@Before) 方法执行之前执行
2) 返回通知 (@AfterReturning) 方法return之后执行
3) 异常通知 (@AfterThrowing) 方法出现异常之后执行
4) 后置通知 (@After) : 又称之为始终要执行finally)
5) 环绕通知 (@Around) :重点掌握
其结构如下:
Try{
@Before
核心业务
@AfterReturning
}catch(Exception e){
@AfterThrowing
}finally{ //执行完finally后再抛出异常
….
@After
}
如上四个一起使用时可以直接使用@Around通知替换
3.2-1注解方式通知配置增强
切入点及前置通知,后置通知,返回通知,异常通知
@Aspect @Service public class LogAspect { @Pointcut("bean(orderServiceImpl)") public void doLog(){} @Before("doLog()") public void doBefore(){ System.out.println("log before"); } @After("doLog()") public void doAfter(){ System.out.println("log after"); } /**核心业务正常结束时执行 * 说明:假如有after,先执行after,再执行returning*/ @AfterReturning("doLog()") public void doAfterReturning(){ System.out.println("log doAfterReturning"); } /**核心业务出现异常时执行 说明:假如有after,先执行after,再执行Throwing*/ @AfterThrowing("doLog()") public void doAfterThrowing(){ System.out.println("log doAfterThrowing"); } }
切入点及环绕通知的配置
@Component @Aspect public class TxManager { @Pointcut("execution(com.company.spring.service..*.*(..))") public void pointCut() {} @Around("pointCut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ try{ System.out.println("事务开始"); Object result = joinPoint.proceed();//执行目标方法 System.out.println("提交事务"); return result; }catch(Exception e){ System.out.println("回滚事务"); throw e; }finally{ System.out.println("释放资源"); } } }
3.2-2切面执行顺序配置增强
注解方式顺序配置需要借助@Order注解
@Order(1) @Aspect @Component public class TxManager { @Pointcut("execution(* com.company.spring.service..*.(..))") public void pointCut() {} @Around("pointCut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("事务开始"); Object result = joinPoint.proceed(); System.out.println("事务结束"); return result; } }
努力终有回报,加油!