Spring-AOP应用

本文介绍了如何在Spring中使用AOP创建自定义注解@OperationLog,配合切面类OperationLogAspect实现在特定接口方法上添加日志记录,简化了日志管理。通过实例展示了如何在删除数据接口上应用此注解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇 Spring-AOP理解讲到aop基于代理对原有方法进行增强,Spring很多注解的都是使用了AOP的动态代理去实现。

例如:

  1. 事务管理 (调用方法前开启事务, 调用方法后提交关闭事务 )
  2. 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
  3. 权限控制(security框架hasAuthority(),hasRole()等)

有时的业务场景需要我们自定义去实现一个切面进行处理。比如记录指定接口的请求响应数据,其实拦截器也可以做到,但是拦截器针对某个接口拦截使用配置相对较麻烦。下面将使用Spring的AOP进行日志记录,当要记录接口的时候添加在接口方法上即可,使用起来也比较简单。

一、定义一个自定义注解
import java.lang.annotation.*;


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {


    String name();
}

二、 切面类进行拦截注解逻辑处理

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.Executor;


@Aspect
@Component
public class OperationLogAspect {

  

    @Pointcut(value = "@annotation(com.xy.annotation.OperationLog)")
    public void aspect() {

    }

    @Around("aspect()&&@annotation(operationLog)")
    public Object around(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        OperationLogSaveReq log = new OperationLogSaveReq();
        log.setName(operationLog.name());
        log.setIp(IpUtils.getLocalIp(request));
        log.setParameter(JSONObject.toJSONString(joinPoint.getArgs()));
        log.setUrl(String.valueOf(request.getRequestURL()));

        Long startTime = System.currentTimeMillis();
        Object obj=null;
        try {
             obj= joinPoint.proceed();
        }catch (Throwable throwable){
            Long endTime = System.currentTimeMillis();
            log.setSpendTime(endTime.intValue()-startTime.intValue());
            log.setResult(JSONObject.toJSONString(throwable.getMessage()));
//            log.setIsSuccess(false);
            saveOperationLog(log);
            throw throwable;
        }
        Long endTime = System.currentTimeMillis();
        log.setSpendTime(endTime.intValue()-startTime.intValue());
        log.setResult(JSONObject.toJSONString(obj));
        if ( obj instanceof ResponseResult){
            log.setIsSuccess(((ResponseResult<?>) obj).isSuccess());
        }else {
            log.setIsSuccess(true);
        }
        saveOperationLog(log);
        return obj;
    }

}

三、需要记录操作日志的地方 添加 @OperationLog 注解。
有必要给这个接口定义一个名称,便于排查日志检索。

    @PostMapping("delete")
    @OperationLog(name = "删除数据")
    public ResponseResult<Void> delete(@RequestBody @Validated BaseIdReq req){
        delete(req.getId());
        return ResponseResult.success();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值