java注解结合aspectj AOP进行日志打印

在很多系统开发中,我们希望在指定的方法调用之前或者之后能打印出该方法的调用时间以及方法的出参和入参,就可以使用spring的AOP,还可以结合自定义的注解进行进行一些指定参数的打印

例如:一个分层的架构系统,每层都有自己的指定系统名字,并且每个方法都有自己指定的作用(通过注解指定,在切面的时候取出该参数),而且可以根据注解的指定日志类型(在注解中指定,在切面的时候取出参数进行判断,然后打印相对应的日志格式)。

  • 1.首先需要自定义注解:
    systemName:表示该系统的名称。
    bizCode:表示具体的方法描述
    logtype:表示日志的格式类型
package myspring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    String systemName();

    String bizCode();

    LogType logtype() default LogType.TIME;
}
  • 2.定义日志格式枚举:
package myspring;

public enum LogType {

    TIME("TIME", "方法调用时间"),
    PARAM("PARAM", "参数打印");

    private String type;
    private String desc;

    LogType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
  • 3.切面代码:
其中execution(* *(..))

第一个* :表示所有返回值
第二个* :表示所有包匹配规则和所有类匹配规则以及所有方法匹配规则
两个点.. :表示任何参数匹配

例如:

execution(* *..*Service.*(..))

表示任何返回值 任何包以Service结尾的类或者实现类的任何方法任何参数
*.. :表示所有包
* :Service表示所有以Service结尾的类或者实现类

execution(* cn.lijie.MyService.*(..))

表示任何返回值 cn.lijie包下面 MyService类或者实现类的所有方法 所有参数

代码如下:

package myspring;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

@Component
@Aspect
public class LogAspect {
    private static Logger thisLog = LoggerFactory.getLogger(LogAspect.class);
    private static Logger timeLog = LoggerFactory.getLogger(TimeTypeLog.class);
    private static Logger paramLog = LoggerFactory.getLogger(ParamTypeLog.class);

    @Around("execution(* *(..)) && @annotation(logAnnotation)")
    public Object log(ProceedingJoinPoint point, LogAnnotation logAnnotation) {
        StopWatch stop = new StopWatch();
        stop.start();
        boolean flag = false;
        Object retValue = null;
        try {
            retValue = point.proceed();
            flag = true;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            stop.stop();
            if (logAnnotation.logtype().equals(LogType.TIME)) {
                timeLog(this.getMethod(point), point, stop.getTotalTimeMillis(), logAnnotation, flag);
            } else {
                paramLog(this.getMethod(point), point, retValue);
            }
        }
        return retValue;
    }

    private void timeLog(String method, ProceedingJoinPoint point, long totalTimeMillis, LogAnnotation logAnnotation, boolean flag) {
        timeLog.info("系统为:{},调用的方法名字:{},调用是否成功:{},运行时间为:{}ms", logAnnotation.systemName(), method, flag, totalTimeMillis);
    }

    private void paramLog(String method, ProceedingJoinPoint point, Object retValue) {
        try {
            String result = JSON.toJSONString(retValue);
            //获取入参
            Object[] args = point.getArgs();
            StringBuffer sb = new StringBuffer();
            for (Object obj : args) {
                String str = JSON.toJSONString(obj);
                sb.append(subStr(str, 200)).append(" ");
            }
            paramLog.info("调用方法为:{},入参为:{},出参为:{}", method, sb, subStr(result, 200));
        } catch (Exception e) {
            thisLog.warn("切面日志 参数日志打印异常,异常信息:{}", e.getMessage());
        }
    }

    private String getMethod(ProceedingJoinPoint pjp) {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        return methodSignature.getDeclaringTypeName() + "#" + methodSignature.getMethod().getName();
    }

    private String subStr(String string, int length) {
        if (!StringUtils.isEmpty(string)) {
            if (string.length() > length) {
                string = string.substring(0, 200);
                return string;
            }
        }
        return string;
    }
}
  • 4.定义一个操作对象:
package myspring;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component("logTest")
public class LogTest {

    private static Logger logger = LoggerFactory.getLogger(LogTest.class);

    @LogAnnotation(systemName = "计算器系统", bizCode = "+", logtype = LogType.TIME)
    public int testLog01(int a, int b) {
        logger.info("进入+运算");
        return a + b;
    }

    @LogAnnotation(systemName = "计算器系统", bizCode = "-", logtype = LogType.PARAM)
    public int testLog02(int a, int b) {
        logger.info("进入-运算");
        return a - b;
    }
}
  • 5.定义两个空类,用于区分不同类型的日志:
package myspring;

public class TimeTypeLog {
}
package myspring;

public class ParamTypeLog {
}
  • 6.spring xml配置文件:
<context:component-scan base-package="myspring"/>
<aop:aspectj-autoproxy/>
  • 7.启动spring的测试类:
package myspring;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        LogTest logTest = (LogTest) context.getBean("logTest");
        logTest.testLog01(1, 2);
        logTest.testLog02(3, 4);
        context.registerShutdownHook();
    }
}
  • 8.pom
<properties>
        <spring_version>4.3.8.RELEASE</spring_version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.11</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.11</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.7</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>
    </dependencies>

最后执行测试的类,日志打印如下:

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值