Springboot中Aop的使用案列

项目问题分析

问题:进行插入,修改操作时存在大量重复代码

使用:Aop将其重复代码封装

创建自定义注解

package com.sky.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;

/**
 * 自定义标识,用于公共字段的填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
//表该注解的参数值
    OperationType value();
}

数据库操作类型用枚举类型表示(减少偶合)

package com.sky.enumeration;

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

创建切点

package com.sky.aspect;

import com.sky.annotation.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.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面,实现公共字段的注解
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 指定切入点
     */
    //切点execution表要扫描的位置,@annotation表要寻找的注解
    @Pointcut("execution(* com.sky.mapper.*.* (..)) && @annotation(com.sky.annotation.AutoFill)")
    //该方法仅用于传参
    public void autofillPointCut() {
    }

    /**
     * 前置通知
     */
    //表在满足autofillPointCut()位置时触发
    @Before("autofillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("前置通知");
        //通过反射获取
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取签名(类)
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取签名下的方法下的注解(注解名.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 {
                //用获取到的参数获取该参数所存在的类,再通过类获取其中的方法(方法名,参数.class)
                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);
                //通过调用invoke方法注入参数
                setCreateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        } else if (operationType == OperationType.UPDATE) {
            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, LocalDateTime.now());
                setUpdateUser.invoke(entity, BaseContext.getCurrentId());
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }

        }

    }

}

其中的涉及到的方法名,提前封装

package com.sky.constant;

/**
 * 公共字段自动填充相关常量
 */
public class AutoFillConstant {
    /**
     * 实体类中的方法名称
     */
    public static final String SET_CREATE_TIME = "setCreateTime";
    public static final String SET_UPDATE_TIME = "setUpdateTime";
    public static final String SET_CREATE_USER = "setCreateUser";
    public static final String SET_UPDATE_USER = "setUpdateUser";
}

将注解添加到书籍要调用的Map方法上

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBootAOP(面向切面编程)可以用于处理以下情况: 1. 日志记录:记录方法的调用时间、方法的参数、返回值等信息,以便于后期的问题排查和优化。 2. 安全控制:对于需要权限控制的方法,可以通过AOP的方式进行统一的访问控制。 3. 性能监控:通过AOP可以实现对方法的性能监控,例如记录方法的执行时间。 4. 事务管理:通过AOP可以实现对事务的统一管理,从而避免因为事务管理不当而导致的数据不一致等问题。 下面我们来看一下在SpringBoot如何使用AOP。 1. 创建切面类 在SpringBoot使用AOP需要创建一个切面类,该类需要使用@Aspect注解进行标识。 ```java @Aspect @Component public class MyAspect { //切入点 @Pointcut("execution(public * com.example.demo.controller.*.*(..))") public void pointcut() { } //前置通知 @Before("pointcut()") public void before() { System.out.println("before method"); } //后置通知 @After("pointcut()") public void after() { System.out.println("after method"); } //返回通知 @AfterReturning("pointcut()") public void afterReturning() { System.out.println("afterReturning method"); } //异常通知 @AfterThrowing("pointcut()") public void afterThrowing() { System.out.println("afterThrowing method"); } } ``` 2. 配置AOP 在配置文件,需要开启AOP的自动配置,同时需要将切面类加入到Spring的容器。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 3. 测试 在controller添加测试代码,测试AOP的功能。 ```java @RestController public class TestController { @GetMapping("/test") public String test() { return "test"; } } ``` 访问/test接口,可以看到控制台输出以下内容: before method after method afterReturning method 至此,我们就完成了在SpringBoot使用AOP的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值