流程
核心概念
自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { OperationType value(); }
关键注解
@Target(ElementType.METHOD)
:指定该注解只能用于方法上。@Retention(RetentionPolicy.RUNTIME)
:指定该注解在运行时保留,可以通过反射读取。
注解属性
OperationType value()
:这是一个属性,类型为OperationType
。通过这个属性,可以指定操作的类型(如插入、更新
切面类
-
@Aspect
:标识该类为一个切面类。 -
@Component
:将该类注册为 Spring 容器中的一个 Bean。 -
@Slf4j
:使用 Lombok 提供的日志注解,自动生成日志对象log
。
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut(){}
-
定义了一个切点
autoFillPointCut()
,用于匹配满足以下条件的方法:-
在
com.sky.mapper
包下的所有类和方法。 -
方法上标注了
@AutoFill
注解。
-
-
execution(* com.sky.mapper.*.*(..))
:匹配com.sky.mapper
包下的所有方法。 -
@annotation(com.sky.annotation.AutoFill)
:匹配标注了@AutoFill
注解的方法。
@Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint){
@Before("autoFillPointCut()")
: 这个注解表示在 autoFillPointCut()
这个切点匹配的方法执行之前,会执行 autoFill
方法
MethodSignature signature = (MethodSignature)joinPoint.getSignature(); AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); OperationType operationType = autoFill.value();
joinPoint.getSignature()
:通过JoinPoint
获取正在执行的方法的签名(Signature
)。Signature
是关于目标方法的信息,例如方法名、返回类型等。(MethodSignature)
:由于joinPoint.getSignature()
返回的是一个通用类型Signature
,而你需要操作的是具体的方法签名,因此需要将其强制转换为MethodSignature
,这个类包含了方法签名相关的详细信息。
signature.getMethod()
:通过MethodSignature
获取目标方法对象(Method
),它包含方法的详细信息。getAnnotation(AutoFill.class)
:从方法对象中获取@AutoFill
注解实例。如果方法上没有这个注解,返回null
。
autoFill.value()
:AutoFill
注解的value
属性返回的是OperationType
枚举类型。根据@AutoFill
注解的定义,value
用来指定当前操作是插入(INSERT
)还是更新(UPDATE
)。通过这行代码,你能够得到这个操作类型。
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Object entity = args[0];
- 获取方法的参数,实体对象,假设第一个参数是实体对象。如果参数为空,直接返回,不进行任何处理。
填充公共字段(INSERT 和 UPDATE)
if(operationType == OperationType.INSERT){ try { Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setCreateUserId = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); Method setUpdateUserId = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); setCreateTime.invoke(entity,now); setUpdateTime.invoke(entity,now); setCreateUserId.invoke(entity,currentId); setUpdateUserId.invoke(entity,currentId); } catch (Exception e) { throw new RuntimeException(e); }
-
反射机制:
getDeclaredMethod
用来获取指定方法名称及参数类型的Method
对象。这里,我们通过反射获取实体类的setter
方法(即setCreateTime
、setUpdateTime
、setCreateUserId
和setUpdateUserId
)。entity.getClass()
是获取实体对象的Class
对象,代表当前实体类的元数据。AutoFillConstant.SET_CREATE_TIME
等是常量,代表方法的名称(如setCreateTime
),这些方法名称通常会事先定义好。LocalDateTime.class
和Long.class
是方法参数的类型,用于匹配setter
方法的参数类型.class
是一个关键字,它用于获取一个类的Class
对象。Class
对象不仅代表了该类本身,而且还提供了该类的详细信息。。
-
invoke
方法:通过Method
对象的invoke
方法调用相应的setter
方法,传入相应的参数值(如当前时间now
和当前用户IDcurrentId
)。setCreateTime.invoke(entity, now)
会调用实体类的setCreateTime(LocalDateTime)
方法,并传入当前时间now
。- 类似的,
setUpdateTime.invoke(entity, now)
调用setUpdateTime(LocalDateTime)
,并传入当前时间。 setCreateUserId.invoke(entity, currentId)
和setUpdateUserId.invoke(entity, currentId)
分别调用setCreateUserId(Long)
和setUpdateUserId(Long)
,并传入当前用户ID。Object obj
: 目标对象,表示你要调用方法的实例。对于静态方法,这个参数可以是null
。Object... args
: 方法的参数列表,使用可变参数形式传入。根据方法签名的不同,args
中的元素会被传递到目标方法。