W aop
aop底层可以理解为动态代理技术,无侵入式给方法增加功能。在aop类中必须加上@Aspect注解
aop主要包含2个方面
1.切入点表达式
有两种方法定义切入点表达式,各部分含义为
返回值 包名 类名 方法名 方法参数
通过方法定义或者直接在通知注解上定义,
//切入点表达式1
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.Annotion.AutoFill)")
public void pointCut(){}
//切入点表达式2
@Around("execution(* com.itheima.service.*.*(..))")
//通知注解
@Before("pointCut()")
2.通知
-
@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
-
@Before:前置通知,此注解标注的通知方法在目标方法前被执行@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
-
@AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
-
@AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行
JoinPoint到底是是个什么玩意?
JoinPoint封装了代理对象,或者叫连接点,@Around中连接点只能是ProceedingJoinPoint
其他通知类型为JoinPoint,ProceedingJoinPoint是JoinPoint的子类。
通过连接点可以获得方法的各种信息。
- Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
- Object[] getArgs(); 获取传入目标方法的参数对象
- Object getTarget(); 获取被代理的对象
- Object getThis(); 获取代理对象
//返回的是代理对象
Object target = joinPoint.getTarget();
log.info("target:{}",target);
Signature signature1 = joinPoint.getSignature();
log.info("singnature:{}",signature1);
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
log.info("MethodSignature:{}",signature);
aop实例:自动添加公共字段,即使用代理调用相关方法,自动完成封装
package com.sky.Aspect;
import com.sky.Annotion.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
@Aspect
@Component
@Slf4j
public class AutoFillAdpect {
/*
切入点表达式
*/
//返回值,包名,类名,方法名,参数名
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.Annotion.AutoFill)")
public void pointCut(){}
/*
通知:前置通知,为公共字段赋值
*/
@Before("pointCut()")
//参数为拦截的方法
public void autoFill(JoinPoint joinPoint) {
log.info("开始公共字段填充");
//获取数据库存操作对象(向下转型
//返回的是代理对象
Object target = joinPoint.getTarget();
log.info("target:{}",target);
Signature signature1 = joinPoint.getSignature();
log.info("singnature:{}",signature1);
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
log.info("MethodSignature:{}",signature);
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
OperationType operationType = autoFill.value();
//获取实体参数,约定实体参数必须放第一个
Object[] args = joinPoint.getArgs();
if (args == null && args.length == 0){
return;
}
//约定实体参数放在方法参数的首位
Object entity = args[0];
//准备数据
LocalDateTime now = LocalDateTime.now();
Long CurrentId = BaseContext.getCurrentId();
//根据不同的方法类型执行不同的封装方法
if (operationType == OperationType.INSERT ){
//四个公共字段赋值
try {
Method createtime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method updatetime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method createuser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method updateuser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//反射赋值
createtime.invoke(entity,now);
updatetime.invoke(entity,now);
createuser.invoke(entity,BaseContext.getCurrentId());
updateuser.invoke(entity,BaseContext.getCurrentId());
} catch (Exception e) {
e.printStackTrace();
}
}else {
//只需要赋值两个公共字段
try {
Method updatetime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method updateuser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//反射赋值
updatetime.invoke(entity,now);
updateuser.invoke(entity,BaseContext.getCurrentId());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}