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; } }