【SpringBoot应用篇】【AOP+注解】SpringBoot使用Aspect AOP基于注解获取方法形参

文章介绍了如何在SpringBoot中使用AOP和注解来实现动态获取方法参数,以便进行日志记录。通过自定义注解@LogPro和切面LogAspectPro,利用反射技术处理不同类型的参数,避免了转换器类的大量创建。当方法参数类型不同时,能动态获取参数值并记录日志。
摘要由CSDN通过智能技术生成

【SpringBoot应用篇】【AOP+注解】SpringBoot使用Aspect AOP基于注解获取方法形参

需求: 需要保存的日志内容在方法的参数中,并且方法参数的类型对象不一样,且对象的属性名称不一样。

【SpringBoot应用篇】SpringBoot使用Aspect AOP注解实现日志管理(增强版)
这一篇文章已经给出了解决方法。但是如果方法的参数不同,会出来转换器类爆炸的情况。
在这里插入图片描述
解决思路: 通过反射技术实现动态获取方法参数
1、@LogPro注解中添加field目标属性字段

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogPro {

    String desc() default "";

    String[] field() default "";

}

2、LogAspectPro切面增强

@Component
@Aspect
public class LogAspectPro {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogAspectPro.class);

    @Pointcut("@annotation(cn.zysheep.anno.LogPro)")
    public void pointcut(){}

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();

        Map<String, Object> paramMap = new HashMap(16);
        Parameter[] parameters = method.getParameters();
        Object[] parameterValues = joinPoint.getArgs();
        if (parameters != null && parameters.length > 0) {
            for (int i = 0; i < parameters.length; ++i) {
                Map<String, Object> subPlaceholder = this.getAttrs(parameters[i], parameterValues[i]);
                paramMap.putAll(subPlaceholder);
            }
        }

        LogPro logPro = method.getAnnotation(LogPro.class);
        if (logPro != null) {
            String[] field = logPro.field();
            String str = (String)paramMap.get(field[0]);
            LOGGER.info("str:{}", str);
        }
    }

    /**
     * 获取参数
     * @param parameter
     * @param value
     *
     * @return
     */
    private Map<String, Object> getAttrs(Parameter parameter, Object value) {
        Map<String, Object> map = new HashMap<>();
        if (parameter.getType().getClassLoader() == null) {
            map = this.getJdkTypeAttrs(parameter, value);
        } else {
            map = this.getCustomObjAttrs(value);
        }
        return map;

    }

    /**
     * 获取jdk自带类型的参数
     * 8种基本数据类型、List、Map
     * @param parameter
     * @param value
     *
     * @return
     */
    private Map<String, Object> getJdkTypeAttrs(Parameter parameter, Object value) {
        Map<String, Object> map = new HashMap<>();
        if (value instanceof Integer
                || value instanceof Long
                || value instanceof Short
                || value instanceof Float
                || value instanceof Byte
                || value instanceof String
                || value instanceof Boolean
                || value instanceof Double) {
            map.put(parameter.getName(), value);
            return map;
        }
        if (value instanceof List) {
            map.putAll(this.getCustomObjAttrs(((List) value).get(0)));
            return map;
        }
        if (value instanceof Map) {
            map.putAll((Map<? extends String, ?>) value);
            return map;
        }
        LOGGER.error("参数类型不支持 type:{}", parameter.getType().getName());
        return map;
    }

    /**
     * 获取自定义对象类型的参数
     *
     * @param object
     * @return
     */
    private Map<String, Object> getCustomObjAttrs(Object object) {
        Map<String, Object> map = new HashMap(16);
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        if (fields != null && fields.length != 0) {
            int length = fields.length;
            for (int i = 0; i < length; ++i) {
                Field field = fields[i];
                try {
                    field.setAccessible(true);
                    Object value = field.get(object);
                    if (value != null) {
                        map.put(field.getName(), value);
                    }
                } catch (Exception e) {
                    LOGGER.warn("读取属性失败", e);
                }
            }
            return map;
        } else {
            return map;
        }
    }


    /**
     * 判断一个类是JAVA类型还是用户定义类型
     * @param clz
     * @return getClassLoader()为null是JAVA类型
     */
    private static boolean isJavaClass(Class<?> clz) {
        return clz != null && clz.getClassLoader() == null;
    }

}

问题:Java反射中Parameter的getName后得到arg0的问题
在这里插入图片描述
解决方法:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>
可以使用 RedisTemplate 实现分布式锁,具体实现步骤如下: 1. 定义一个自定义注解,用于标识需要加锁的方法。 2. 在方法执行前获取锁,执行后释放锁。 3. 使用 RedisTemplate 操作 Redis,实现分布式锁。 下面是示例代码: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DistributedLock { String key(); long expire() default 30000; } @Component @Aspect public class DistributedLockAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Around("@annotation(distributedLock)") public Object doAround(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { String key = distributedLock.key(); long expire = distributedLock.expire(); // 获取锁 boolean locked = false; String lockKey = "lock:" + key; String lockValue = UUID.randomUUID().toString(); try { locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expire, TimeUnit.MILLISECONDS); if (!locked) { throw new RuntimeException("获取锁失败"); } // 执行方法 return joinPoint.proceed(); } finally { // 释放锁 if (locked) { String value = redisTemplate.opsForValue().get(lockKey); if (lockValue.equals(value)) { redisTemplate.delete(lockKey); } } } } } ``` 在需要加锁的方法上加上 @DistributedLock 注解,指定锁的 key 和过期时间即可。 例如: ```java @Service public class UserService { @Autowired private UserDao userDao; @DistributedLock(key = "user:update:${#userId}") public void updateUser(long userId, String name) { userDao.updateUser(userId, name); } } ``` 这样就可以实现分布式锁了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李熠漾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值