Aop示例之注解切面方式实现日志打印

在使用切面前,首先保证项目配置启动对@AspectJ注解的支持及监听类,在Spring的配置文件中,添加如下配置即可:

<!-- 启动对@AspectJ注解的支持  -->
<aop:aspectj-autoproxy proxy-target-class="true" />

 

示例:

 

import cn.hutool.json.JSONUtil;
import com.credithc.openapi.flowplatform.basedto.BaseResp;
import com.credithc.openapi.flowplatform.enums.ResultCodeEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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 java.util.Arrays;

/**
 * 针对base服务模块api的日志打印切面
 *
 * @author kuangxiang
 * @date 2020/10/27 10:55
 */
@Aspect
@Component
public class LogForBaseApiAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 定义切点
     * <p>
     * 作用是供通知方法知道需要在何处执行通知
     * execution:可以是个包路径,例如本示例中;也可以是自定义的注解
     * </P>
     */
    @Pointcut("execution(* com.credithc.openapi.flowplatform.dubboapi.*.*(..)) || " +
            "execution(* com.credithc.openapi.flowplatform.service.impl.*.*(..)) || " +
            "execution(* com.credithc.openapi.flowplatform.controller.*.*(..))")
    public void point() {
    }

    /**
     * 环绕通知
     * <p>
     * 1.在目标方法执行前和执行后都会执行此方法
     * 2.接口中的参数对应ProceedingJoinPoint而不是JoinPoint,是因为 ProceedingJoinPoint继承了JoinPoint是在JoinPoint的基础上暴露出proceed 这个方法 ,
     * 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。
     * </P>
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("point()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        String substring = className.substring(className.lastIndexOf(".") + 1);
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        String methodName = signature.getName();
        Object[] args = proceedingJoinPoint.getArgs();

        logger.info("【流量增益平台】【{}.{}】请求开始,req:{}", substring, methodName, Arrays.toString(args));

        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = proceedingJoinPoint.proceed();
        // 执行时长(毫秒)
        long costTime = System.currentTimeMillis() - beginTime;

        logger.info("【流量增益平台】【{}.{}】请求结束,req:{},result:{},执行时间:【{}】毫秒", className, methodName, Arrays.toString(args),
                JSONUtil.toJsonStr(result), costTime);
        return result;
    }

    /**
     * 目标方法执行前执行
     *
     * @param joinPoint 切点对象
     */
    @Before("point()")
    public void before(JoinPoint joinPoint) {

    }

    /**
     * 目标方法正常结束后执行
     *
     * @param joinPoint 切点对象
     * @param resp      这个参数定义目标方法响应结果参数名,和@AfterReturning注解中returening属性的值是一致的
     */
    @AfterReturning(returning = "resp", pointcut = "point()")
    public void afterReturn(JoinPoint joinPoint, Object resp) {

    }

    /**
     * 目标方法非正常结束时打印
     *
     * @param throwable 异常信息,此参数是方法执行中抛出的异常信息,和@AfterThrowing注解中throwing属性的值是一致的
     */
    @AfterThrowing(value = "point()", throwing = "throwable")
    public BaseResp afterThrowing(Throwable throwable) {
        BaseResp result=new BaseResp(ResultCodeEnum.R500);
        logger.error("【流量增益平台】【{}.{}】请求异常,req:{},",throwable);
        return result;

    }
}

 

posted @ 2020-09-16 11:59  海棠--依旧  Views(722)  Comments(0Edit  收藏  举报