springboot-使用自定义注解+spring aop实现日志记录

  aop面向切面编程算是spring中比较重要的概念。恰好最近在开发过程中有通过aop+自定义注解来实现日志功能的想法,特此记录。

  1. 引入相关依赖,这边主要是引入spring boot相关的起步依赖,javassist用来获取入参信息。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zwj</groupId>
    <artifactId>aopdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aopdemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


  1. 自定义一个注解类
package com.zwj.aopdemo.annotation;

import java.lang.annotation.*;

/**
 * 自定义日志注解
 * @author zev.zhang
 * @version V1.0.0
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    String description() default "";
}

  1. 编写切面类,在建好的切面类上使用@Aspect和@Component注解,@Component注解将建立的切面类注入spring容器,@Aspect注解将该类标注为切面类,来实现前置通知、后置通知、返回通知、异常通知、环绕通知。使用@PointCut注解定义切入点,切入点即为刚刚建好的自定义注解@SysLog。
  • 前置通知 :@Before,即在目标方法执行之前运行该方法体的内容。
  • 后置通知 :@After,即在目标方法运行之后运行该方法体的内容。
  • 返回通知 :@AfterReturning,即在方法返回后运行该方法体的内容。
  • 异常通知 :@AfterThrowing,即在方法发生异常后运行该方法体的内容。
  • 环绕通知 : @Around,即在目标方法执行前和执行后都运行该方法体的内容。
package com.zwj.aopdemo.aspect;

import com.alibaba.fastjson.JSONObject;
import com.zwj.aopdemo.util.LogAopUtil;
import javassist.NotFoundException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @version 1.0.0
 * @description:
 * @author: Zev.Zhang
 * @date: 2019/12/18 9:05 下午
 */
@Aspect
@Component
public class LogAspect {

    private Logger log = LoggerFactory.getLogger(LogAspect.class);
    //方法开始时间
    private long startTimeMillis = 0;
    //方法结束时间
    private long endTimeMillis = 0;

    /**
     * @desc 定义切入点
     */
    @Pointcut("@annotation(com.zwj.aopdemo.annotation.SysLog)")
    public void addLog() {
    }

    /**
     * @desc 前置通知
     */
    @Before("addLog()")
    public void doBeforeExec() {
        startTimeMillis = System.currentTimeMillis();
        log.info("方法开始..........");
    }

    @After("addLog()")
    public void doAfterExec() {
        endTimeMillis = System.currentTimeMillis();
        log.info("方法结束..........");
    }

    @AfterReturning(pointcut = "addLog()", returning = "ret")
    public void doAfterReturning(JoinPoint joinPoint, Object ret) throws ClassNotFoundException, NotFoundException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        StringBuffer requestURL = request.getRequestURL();
        log.info("请求路径:"+requestURL.toString());
        Object[] args = joinPoint.getArgs();
        String classType = joinPoint.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        // 获取方法名称
        String methodName = joinPoint.getSignature().getName();
        // 获取参数名称和值
        String innerText = LogAopUtil.getNameAndArgs(this.getClass(), clazzName, methodName, args).toString();
        log.info("请求类方法参数名称和值:" + innerText);
        //返回值
        String outerText = ret.toString();
        //执行时间
        Long excuteTime = endTimeMillis - startTimeMillis;
        log.info("入栈[INNERTEXT]:{},[OUTERTEXT]:{},[EXCUTETIME]:{}", innerText, outerText, excuteTime);


    }


}
  1. 编写一个rest接口进行测试
package com.zwj.aopdemo.controller;

import com.zwj.aopdemo.annotation.SysLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @version 1.0.0
 * @description:
 * @author: Zev.Zhang
 * @date: 2019/12/18 9:40 下午
 */
@RestController
public class TestController {

    @SysLog
    @GetMapping("/test")
    public String test(String name){
        try {
            Thread.sleep(100L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "进入接口 /test";
    }
}
  1. 启动项目,调用接口查看返回结果。
2019-12-18 22:16:18.621  INFO 41818 --- [nio-8080-exec-4] com.zwj.aopdemo.aspect.LogAspect         : 方法开始..........
2019-12-18 22:16:18.723  INFO 41818 --- [nio-8080-exec-4] com.zwj.aopdemo.aspect.LogAspect         : 方法结束..........
2019-12-18 22:16:18.723  INFO 41818 --- [nio-8080-exec-4] com.zwj.aopdemo.aspect.LogAspect         : 请求路径:http://localhost:8080/test
2019-12-18 22:16:18.723  INFO 41818 --- [nio-8080-exec-4] com.zwj.aopdemo.aspect.LogAspect         : 请求类方法参数名称和值:{"name":"aaa"}
2019-12-18 22:16:18.723  INFO 41818 --- [nio-8080-exec-4] com.zwj.aopdemo.aspect.LogAspect         : 入栈[INNERTEXT]:{"name":"aaa"},[OUTERTEXT]:进入接口 /test,[EXCUTETIME]:102ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值