AOP实现日志记录

AOP实现日志记录
自定义注解方式 实现

1、总体图

在这里插入图片描述
2、注解类SystemLog

SystemLog
在这里插入图片描述

package com.sangeng.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) //@SystemLog注解 保持到 runtime阶段
@Target({ElementType.METHOD})   //指定@SystemLog注解 加在method上,表示某个method受aop切面增强
public @interface SystemLog {
    //使用aop,1.写  自定义注解 @SystemLog
    String businessName(); //属性,指定业务名称 “更新用户信息”
}

3、切面类LogAspect
handleBefore 在请求执行之前 执行这个方法
handleAfter 在请求执行之后 执行这个方法
在这里插入图片描述

LogAspect

package com.sangeng.aspect;
import com.alibaba.fastjson.JSON;
import com.sangeng.annotation.SystemLog;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Component //切面类要注入spring容器
@Aspect    //告诉spring这是 一个切面类
@Slf4j  // log日志
public class LogAspect {
    //使用aop,2. 定义切面类LogAspect
//切面 = 切点 + 通知

    // 2.1确定切点(重点:在方法上加注解,指定切点)  注解方式(写自定义注解@SystemLog的全类名)
    @Pointcut("@annotation(com.sangeng.annotation.SystemLog)") //自定义注解SystemLog的 全类名
    public void pt(){
//    被增强方法,目标方法:controller中 @PutMapping("/userInfo")对应的方法
//joinPoint:被增强方法(目标方法)的信息 封装成一个对象
    }

    // 2.2通知方法 (增强的代码)
    @Around("pt()")  //环绕通知:指定使用的切点---指定pt()方法上所使用的切点
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable { //joinPoint:被增强方法(目标方法)的信息 封装成一个对象
//        环绕通知是前置,执行,异常,最终四个通知

        Object ret; //Around必须调用proceed()让目标方法执行,不然目标方法不会执行
        try {
            handleBefore(joinPoint);//目标方法之前 执行
            ret = joinPoint.proceed();  //这个异常,这里不能用try-catch,否则controller层的异常都在这被捕获了,so,要往上抛出异常
            handleAfter(ret); //目标方法之后 执行    参数ret是目标方法执行后返回ResponseResult类型
        } finally { //最终 都要执行的代码:打印日志信息
            // 结束后换行
            log.info("=======End=======" + System.lineSeparator()); //System.lineSeparator()获取当前系统换行符
        }
        return ret; //目标方法执行后,要有返回值,不然目标方法没有返回值
    }
    private void handleBefore(ProceedingJoinPoint joinPoint) {
//        看到类名后面有Holder 一般表示这个类 使用ThreadLocal进行数据共享,保证多个线程之间资源的隔离
//        RequestAttributes -> ServletRequestAttributes(实现类) 可以获取request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest(); //得到request

        //获取被增强方法上的注解对象  被增强方法:controller中 @PutMapping("/userInfo")对应的方法
        SystemLog systemLog = getSystemLog(joinPoint); // 需要joinPoint对象

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}",request.getRequestURL()); //获取当前线程请求对象, url是在request对象当中(URL在http报文的request部分)
        // 打印描述信息  业务名字,接口名字
        log.info("BusinessName   : {}", systemLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法   类名 方法名
        log.info("Class Method   : {}.{}",joinPoint.getSignature().getDeclaringType(),
                ((MethodSignature) joinPoint.getSignature()).getName());
        // 打印请求的 IP
        log.info("IP             : {}",request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", JSON.toJSONString(joinPoint.getArgs())); //数组转成json字符串
    }

    private void handleAfter(Object ret) {
        // 打印出参
        log.info("Response       : {}",JSON.toJSONString(ret) );
    }

    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
//    被增强方法,目标方法:controller中 @PutMapping("/userInfo")对应的方法
//joinPoint:被增强方法(目标方法)的信息 封装成一个对象,叫做签名Signature
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取目标方法
        SystemLog systemLog = signature.getMethod().getAnnotation(SystemLog.class);
        return systemLog;
    }

}

4、测试
运行项目,访问 @PutMapping(“/user/userInfo”) 即可打印日志信息。
这个请求之前的日志 -> handleAfter
这个请求之后的日志 -> handleBefore

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP是一个强大的框架,可以帮助我们实现各种切面,其中包括日志记录。下面是实现日志记录的步骤: 1. 添加Spring AOP依赖 在Maven或Gradle中添加Spring AOP依赖。 2. 创建日志切面 创建一个用于记录日志的切面。这个切面可以拦截所有需要记录日志的方法。在这个切面中,我们需要使用@Aspect注解来声明这是一个切面,并使用@Pointcut注解来定义哪些方法需要被拦截。 ```java @Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void serviceMethods() {} @Around("serviceMethods()") public Object logServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法名,参数列表等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 记录日志 System.out.println("Method " + methodName + " is called with args " + Arrays.toString(args)); // 执行方法 Object result = joinPoint.proceed(); // 记录返回值 System.out.println("Method " + methodName + " returns " + result); return result; } } ``` 在上面的代码中,我们使用了@Around注解来定义一个环绕通知,它会在拦截的方法执行前后执行。在方法执行前,我们记录了该方法的名称和参数列表,然后在方法执行后记录了该方法的返回值。 3. 配置AOPSpring的配置文件中配置AOP。首先,我们需要启用AOP: ```xml <aop:aspectj-autoproxy/> ``` 然后,我们需要将创建的日志切面添加到AOP中: ```xml <bean id="loggingAspect" class="com.example.demo.aspect.LoggingAspect"/> <aop:config> <aop:aspect ref="loggingAspect"> <aop:pointcut id="serviceMethods" expression="execution(* com.example.demo.service.*.*(..))"/> <aop:around method="logServiceMethods" pointcut-ref="serviceMethods"/> </aop:aspect> </aop:config> ``` 在上面的代码中,我们将创建的日志切面声明为一个bean,并将其添加到AOP中。我们还定义了一个切入点,并将其与日志切面的方法进行关联。 4. 测试 现在,我们可以测试我们的日志记录功能了。在我们的业务逻辑中,所有匹配切入点的方法都会被拦截,并记录它们的输入和输出。我们可以在控制台中看到这些日志信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值