【开发心得】基于切面实现事件记录

环境:

Spring boot 2.x

依赖:

直接引入AOP starter 

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

或者单独引入以下两个依赖

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

apache-common-lang3依赖

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
</dependency>

 

关于启动类添加@EnableAspectJAutoProxy注解。如果直接引入AOP starter 默认可以不手动开启(约定配置里默认开启了),当然可以手动使用该注解,或者在application.yml使用配置方式开启。

1.如果需要半侵入方式记录数据。则需要自定义注解。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventTracking {
    String tableName(); // 表名
    DbEventType type(); // 类型
    String relatedId(); // id
}

2.切面类

 切点:

2.1 基于注解的切点

    @Pointcut("@annotation(com.xxxx.EventTracking)")
    public void beforePointCut() {
    }

2.2 基于切点表达式的切点 (切点表达式很多写法,可以使用通配符模糊匹配)

@Pointcut("execution(* com.xxxx.update(com.xxxx.xxTask))")
    public void beforexxxUpdate() {
    }

切面:(多个表达式之间使用|| && 以及 or and 等符号连接)

@Before("beforexxxxUpdate() || beforeFaceUpdate()")
public void getTrackingInfoBeforeByExecution(JoinPoint joinPoint){}

珠玑:

获取注解值与传参参数。首先要知道MethodSignature的getParameterNames能够拿到全部的参数名称。然后JoinPoint可以获取到Args参数数组。这里使用的ArraysUtils.indexOf是apache lang3的方法,请自行引入。

// 获取埋点所需参数
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        EventTracking annotation = signature.getMethod().getAnnotation(EventTracking.class);
        String tableName = annotation.tableName();
        DbEventType type = annotation.type();
        String relatedData = annotation.relatedData();
        // 参数名数组
        String[] parameters = signature.getParameterNames();
        // 参数值
        Object[] args = joinPoint.getArgs();
        Long rId = null;
        int index = ArrayUtils.indexOf(parameters, relatedData);
        if (index != -1) {
            Object obj = args[index];
            if (obj == null) {
                return;
            }
            JSONObject jsonObject = (JSONObject) JSONObject.toJSON(obj);
            String idString = jsonObject.getString("id");
            if (StringUtils.isBlank(idString)) {
                return;
            }
            rId = Long.valueOf(String.valueOf(idString)).longValue();
            eventTrackingService.buildEventTrackingData(tableName, rId, type);
        }

3. 当然可以根据参数 直接不使用注解的方式进行实现,无非需要根据函数名或者完全遍历参数的情况下进行获取。

关于AOP的基础知识这里不做分享, 关于 @Around @Before @After等切面方式也请自行学习。

本文主要分享的是一个基于Springboot2.x的AOP实现以及在AOP使用过程中的小技巧。

posted @ 2021-06-07 18:41  虹梦未来  阅读(3)  评论(0编辑  收藏  举报  来源