AOP(Aspect-Oriented Programming)面向切面编程
是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充,是一种通过动态代理实现程序功能扩展和统一维护的一种技术
OOP:面向对象编程,纵向继承机制,重点关注类
AOP:面向切面编程,横向提取机制,重点关注方法
一、动态代理原理:一个代理将原本的对象包装起来,然后用该代理对象“取代”原始对象。任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
二、AOP1、准备工作
org.springframework
spring-aspects
5.3.1
2、AOP术语:
(1)横切关注点:非核心业务称为横切关注点
(2)切面:将横切关注点提取到类中,类称为切面
(3)通知:将横切关注点提取到类中后,横切关注点更名为:通知
(4)目标
(5)代理
@Autowired
private Calc calc; //com.sun.proxy.$Proxy21
(6)连接点
(7)切入点
3、AOP切入点表达式
(1) 基本语法
execution( [权限修饰符] [返回值类型] [简单类名/全类名] [方法名] ( [参数列表类型] )
execution(public int com.atguigu.annotationAspectJ.CalcImpl.add(int,int))
(2) 表达式常用通配符
【*】:可以代表任意权限修饰符和返回值类型 ; 任意包 | 任意类全限定名 ; 任意方法名
【..】:代表任意参数类型 | 参数数量
(3) 重用切入点表达式
提取公共切入点表达式
@Pointcut("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
public void myPointCut(){
}
提取后的方法名,作为切入点表达式
@Before("myPointCut()")
public void methodBefore(JoinPoint joinPoint){
(4)AspectJ中支持通知
- 前置通知:@Before
在业务代码执行前执行,如有异常也执行
@Pointcut("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
public void myPointCut(){
}
//@Before("execution(public int com.atguigu.annotationAspectJ.CalcImpl.add(int,int))")
@Before("myPointCut()")
public void methodBefore(JoinPoint joinPoint){
//通过方法签名【方法名形参列表】,获取方法名
String name = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("日志功能【前置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
}
- 后置通知:@After
在业务代码执行之后执行,如有异常也执行
@After("execution(* com.atguigu.annotationAspectJ.CalcImpl.*(..))")
public void methodAfter(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("日志功能【后置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
}
- 返回通知:@AfterReturning
在业务代码返回结果后<后置通知之前>执行,如有异常不执行
返回通知要求,returning="属性值"与入参中参数名一致
@AfterReturning(value = "myPointCut()",returning = "rs")
public void methodReturn(JoinPoint joinPoint,Object rs){
String name = joinPoint.getSignature().getName();
System.out.println("日志功能【返回通知】:执行"+name+"()方法,返回结果rs:"+ rs);
}
- 异常通知:@AfterThrowing
在业务代码出现异常时<后置通知之前>执行,如有异常执行;无异常不执行
异常通知要求,throwing="属性值"与参数名一致
@AfterThrowing(value = "myPointCut()",throwing = "ex")
public void methodThrowing(JoinPoint joinPoint,Exception ex){
String name = joinPoint.getSignature().getName();
System.out.println("日志功能【异常通知】:执行"+name+"()方法,出现异常ex:"+ ex);
}
- 环绕通知:@Around
将业务代码<前置 | 后置 | 返回 | 异常>通知,整合一处
环绕通知的参数,只能ProcessingJoinPoint
@Around(value = "myPointCut()")
public Object methodAround(ProceedingJoinPoint proceedingJoinPoint){
Object rs = null;
//获取方法名
String name = proceedingJoinPoint.getSignature().getName();
//获取参数
Object[] args = proceedingJoinPoint.getArgs();
try {
//前置通知
System.out.println("日志功能【前置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
//执行目标对象的目标方法【add()】
Object object = proceedingJoinPoint.proceed();
//返回通知
System.out.println("日志功能【返回通知】:执行"+name+"()方法,返回结果rs:"+ rs);
} catch (Throwable ex) {
ex.printStackTrace();
System.out.println("日志功能【异常通知】:执行"+name+"()方法,出现异常ex:"+ ex);
} finally {
//后置通知
System.out.println("日志功能【后置通知】:执行"+name+"()方法之前,参数:"+ Arrays.toString(args));
}
return rs;
}
(5)切面优先级
@Order(value=index) index=正整数
作用:设置切面优先级 ,数值越小,优先级越高
@Component //将当前类装配IOC容器中
@Aspect //将当前类标识为一个切面【】
@Order(value = 2)
public class MyLogging {
}
@Component
@Aspect
@Order(value = 1)
public class MyValidate {
}



