目录
AOP
介绍
AOP是一种面向切面编程的范式,AOP通过动态代理的方式实现对方法的拦截和处理。在运行时,AOP框架会自动生成代理对象,将切面逻辑织入到目标对象的方法中,实现对方法的增强和修改。通过将横切关注点从主要业务逻辑中分离出来,提高了代码的可读性、可维护性和可重用性。它通过切面和连接点的概念来实现,可以用于解决许多常见的横切关注点问题
实现步骤
-
自定义注解AutoFIll,用于表示需要进行公共字段自动填充的方法
-
自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法
-
在Mapper的方法中加入AutoFill注解
什么情况下使用
当我们设计到多个共同操作时可以使用,比如在插入和更新数据时,我们需要为实体类添加当地时间以及操作人的userid,我们可以在service中涉及到该操作的方法添加我们自定义的注解,然后在自定义的切面类中获取方法的一些数据,并根据请求方法来进行不同的反射操作
自定义的注解
自定义注解annotation
import com.sky.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解,用于标识某个方法需要进行字段自动填充
*/
@Retention(RetentionPolicy.RUNTIME) //保留到运行阶段
@Target(ElementType.METHOD) //只能加在方法上
public @interface AutoFill {
// 数据库操作类型
OperationType value();
}
//OperationType为枚举类型,我们需要对update和insert进行拦截
public enum OperationType {
UPDATE,
INSERT
}
自定义切面类AutoFillAspect
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
/**
* 切入点
* com.sky.mapper包下包含AutoFill注解的所有类和方法
*/
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut() {
}
/**
* 前置通知,在通知中进行公共字段的赋值
*/
//@Before 当autoFillPointCut扫描到带有AutoFill方法时,执行这里
@Before("autoFillPointCut()")
public void autoFill(JoinPoint joinPoint) {
log.info("开始进行公共字段自动填充");
// 获取到当前拦截的方法上的数据库操作类型获取方法签名对象
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//获取方法上的注解对象
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) {
// 为4个公共字段赋值
try {
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 通过反射为对象赋值
setCreateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (operationType == operationType.UPDATE) {
// 为2个公共字段赋值
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
// 通过反射为对象赋值
setUpdateTime.invoke(entity, now);
setUpdateUser.invoke(entity, currentId);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
在Mapper的方法中加入AutoFill注解
//添加AutoFill可以被AutoFillAspect拦截
//添加AutoFill可以被AutoFillAspect拦截
@AutoFill(OperationType.INSERT)
void insert(Employee employee);
@AutoFill(OperationType.UPDATE)
void update(Employee employee);