【SpringBoot应用篇】【AOP+注解】SpringBoot使用Aspect AOP注解实现日志管理(增强版)

【SpringBoot应用篇】【AOP+注解】SpringBoot使用Aspect AOP注解实现日志管理(增强版)


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

解决思路:
1、添加类型转换器Convert接口,需要转换的类型继承Convert接口
2、@Log注解中添加Convert接口类型的Class属性
3、在切面环绕通知中进行处理

pom

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
</parent>

<dependencies>
	<dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-aop</artifactId>
	</dependency>
	
	<dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	
	<dependency>
	  <groupId>org.projectlombok</groupId>
	  <artifactId>lombok</artifactId>
	</dependency>
</dependencies>

Log

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
    String desc() default "";
    Class<? extends Convert> convert();
}

实体类

OperateLog

@Data
public class OperateLog {
    private String id;
    private String desc;
    private String result;
}

Order

@Data
public class Order {
    private String orderId;
}

Good

@Data
public class Good {
    private String goodId;
}

LogAspect

@Component
@Aspect
public class LogAspect {
    static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    static final ExecutorService executorService = new ThreadPoolExecutor(
            1,
            1,
            10 ,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());


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


    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = proceedingJoinPoint.proceed();
        executorService.execute(()->{
            try {
                MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
                Method method = signature.getMethod();
                Log log = method.getAnnotation(Log.class);
                if (log != null) {
                    Class<? extends Convert> convert = log.convert();
                    Convert instance = convert.newInstance();
                    OperateLog operateLog = instance.convert(proceedingJoinPoint.getArgs()[0]);
                    operateLog.setDesc(log.desc());
                    operateLog.setResult(result.toString());
                    logger.info("save operateLog: {}", operateLog);
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
        return result;
    }
}

转换器

Convert

public interface Convert<T> {
    OperateLog convert(T t);
}

GoodConvert

public class GoodConvert implements Convert<Good> {
    @Override
    public OperateLog convert(Good updateOrder) {
        OperateLog operateLog = new OperateLog();
        operateLog.setId(updateOrder.getGoodId());
        return operateLog;
    }
}

OrderConvert

public class OrderConvert implements Convert<Order> {
    @Override
    public OperateLog convert(Order saveOrder) {
        OperateLog operateLog = new OperateLog();
        operateLog.setId(saveOrder.getOrderId());
        return operateLog;
    }
}

AopController

@RestController
public class AopController {

    @GetMapping("/saveOrder")
    @Log(desc = "保存订单", convert = OrderConvert.class)
    public String saveOrder(Order order) {
        System.out.println(order);
        return "ok";
    }

    @GetMapping("/saveGood")
    @Log(desc = "保存商品", convert = GoodConvert.class)
    public String saveGood(Good good) {
        System.out.println(good);
        return "ok";
    }
}

启动类

@SpringBootApplication
public class AopApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopApplication.class, args);
    }
}

1、页面访问: http://localhost:8080/saveOrder?orderId=2
2、页面访问: http://localhost:8080/saveGood?goodId=1231
在这里插入图片描述
不同类型不同属性名称的值保存到了操作日志对象的id中

@EnableAutoOperateLog

使用SpringBoot自动配置的原理,启用热拔插效果

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({LogAspect.class})
public @interface EnableAutoOperateLog {
}

1、LogAspect 切面类去除@Component注解,保留@Aspect,否则切面不生效
2、启动类添加@EnableAutoOperateLog

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
可以使用 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); } } ``` 这样就可以实现分布式锁了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李熠漾

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

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

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

打赏作者

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

抵扣说明:

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

余额充值