自定义注解:有入参的注解&实现打印接口入参


前言

写此文章的目的:
1:工作上遇到使用自定义注解进行分布式锁,注解可以传入参数。(必须记录这种高级用法)
2:重写下AOP实现打印接口入参(以前的写的不好)

一、pom依赖

整个项目就只有这么点依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

二、自定义注解(有入参)

示例:

方法上的注解:
@ParamAnnotation(lockKey = "#userRequest.name,#userRequest.jobRequest.jobName",expireTime = 1500)

入参:
{
    "name":"lt-test paramAnnotation",
    "jobRequest":{
        "jobId":"123456789",
        "jobName":"oooooo"
    }
}

解析获取到的值是一个List<String>:
["lt-test paramAnnotation","oooooo"]

1.定义注解

代码如下(示例):

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 ParamAnnotation {

    /**
     * 分布式锁 key
     */
    String lockKey();

    /**
     * 分布式锁 value
     */
    String lockValue() default "lockValue";

    /**
     * 分布式锁 过期时间
     */
    int expireTime() default 300;
}

2.注解的Aspect


import com.tao.demo.annotation.ParamAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Aspect
@Component
@Slf4j
@Order(2)
public class ParamAnnotationAspect {
    private static LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    /**
     * Around 环绕增强通知
     *
     * @param joinPoint 连接点,所有方法都属于连接点;但是当某些方法上使用了@PrintLog自定义注解时,
     *                  则其将连接点变为了切点;然后在切点上织入额外的增强处理;切点和其相应的增强处理构成了切面Aspect 。
     */
    @Around("@annotation(com.tao.demo.annotation.ParamAnnotation)")
    public Boolean handlerPrintLog(ProceedingJoinPoint joinPoint) {
        ParamAnnotation paramAnnotation = ((MethodSignature) joinPoint.getSignature())
                .getMethod().getAnnotation(ParamAnnotation.class);

        // 获取自定义注解对象中的属性值
        String lockKey = paramAnnotation.lockKey();
        String lockValue = paramAnnotation.lockValue();
        int expireTime = paramAnnotation.expireTime();


        log.info("lockKey = {}", getLockKey(lockKey));
        log.info("lockValue = {}", lockValue);
        log.info("expireTime = {}", expireTime);

        Object target = joinPoint.getTarget();
        Method method = this.joinPointMethod(joinPoint);
        Object[] param = joinPoint.getArgs();

        List<String> str = parseKeyELs(lockKey,target,method, param);
        log.info("获取注解入参里的lockKey对应的值:{}",str);
        //可以在这里调用redisService获取分布式锁
//        if (redisService.tryGetDistributedLock(lockKey, LockValue, expireTime)) {
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            //释放分布式锁
            log.info("释放分布式锁");
        }
//        }
        return false;
    }

    private List<String> parseKeyELs(String keyEL, Object target, Method method, Object[] args) {
        if (StringUtils.isEmpty(keyEL)) {
            return Collections.emptyList();
        } else {
            List<String> keyELs = Arrays.asList(keyEL.split(","));
            return (List) keyELs.stream().map((spVal) -> {
                return parseEL(spVal, target, method, args);
            }).collect(Collectors.toList());
        }
    }
    private Method joinPointMethod(ProceedingJoinPoint point) {
        return ((MethodSignature)point.getSignature()).getMethod();
    }

    public static String parseEL(String spEL, Object root, Method method, Object[] args) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new MethodBasedEvaluationContext(root, method, args, discoverer);
        if (null != args && args.length > 0) {
            String[] names = discoverer.getParameterNames(method);

            for (int i = 0; i < names.length; ++i) {
                context.setVariable(names[i], args[i]);
            }
        }

        return (String) parser.parseExpression(spEL).getValue(context, String.class);
    }

    private String getLockKey(String lockKey) {
        StringBuilder stringBuilder = new StringBuilder("redisLockKey");
        List<String> keyList = Arrays.asList(lockKey.split(","));
        keyList.forEach(key -> {
            stringBuilder.append(":").append(key);
        });
        return stringBuilder.toString();
    }

}

二. 打印入参

1.定义注解

代码如下(示例):

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 PrintLog {
}

2.注解的Aspect

@Aspect
@Component
@Slf4j
@Order(1)
public class PrintLogAspect {
    /**
     *  Around 环绕增强通知
     *
     * @param joinPoint 连接点,所有方法都属于连接点;但是当某些方法上使用了@PrintLog自定义注解时,
     *                  则其将连接点变为了切点;然后在切点上织入额外的增强处理;切点和其相应的增强处理构成了切面Aspect 。
     */
    @Around("@annotation(com.tao.demo.annotation.PrintLog)")
    public Object handlerPrintLog(ProceedingJoinPoint joinPoint) {
        // 获取方法的名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法入参
        Object[] param = joinPoint.getArgs();

        StringBuilder sb = new StringBuilder();
        for (Object o : param) {
            sb.append(o).append("; ");
        }
        log.info("-----");
        log.info("进入《{}》方法, 参数为: ", methodName);
        log.info(JSONObject.toJSONString(sb));
        log.info("-----");

        Object object = null;
        // 继续执行方法
        try {
            object = joinPoint.proceed();

        } catch (Throwable throwable) {
            log.error("打印日志处理error。。", throwable);
        }
        log.info("{} 方法执行结束。。", methodName);
        return object;
    }

}

三. controller

/**
 * @author lobster.long
 * @date 2022/6/14
 */
@Slf4j
@RestController()
@RequestMapping("demo")
public class DemoController {


    @PrintLog
    @PostMapping(value = "test")
    public void test(@RequestBody UserRequest userRequest){
      log.info(JSONObject.toJSONString(userRequest));
    }


    @ParamAnnotation(lockKey = "#userRequest.name,#userRequest.jobRequest.jobName",expireTime = 1500)
    @PostMapping(value = "paramAnnotation")
    public void paramAnnotation(@RequestBody UserRequest userRequest){
        log.info(JSONObject.toJSONString(userRequest));
    }
}

四. request

请求对象:UserRequest

@Data
public class UserRequest {
    private String name;

    private JobRequest jobRequest;
}

请求对象:JobRequest

@Data
public class JobRequest {
    private String jobId;
    private String jobName;
}

执行结果

1.@ParamAnnotation结果

在这里插入图片描述

2.@PrintLog结果

在这里插入图片描述

总结

支持入参的注解,感觉很高级的样子 ~ ~
陌生人,加油,一起学习进步。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值