在实际的业务系统中,我们通常都希望程序自动的打印方法的入参和返回值,某些特定的方法可能不想打印返回值(返回数据过大,打印日志影响效率),特有了下面的实现。

1、忽略返回值的java注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 不需要打印返回值的log
* @author yangzhilong
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NotPrintResponseLog {
public boolean value() default false;
}

2、日志记录切面类

 import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; 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.multipart.MultipartFile; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; /**
* 记录Rest和service的方法的入参和返回值
   * @author yangzhilong
*/
@Aspect
@Component
@Slf4j
public class CommonLogAspect {
@Pointcut(value = "execution(public * com.tomato..*Impl.*(..))")
private void pointcutService() { }
@Pointcut(value = "execution(public * com.tomato..*Rest*.*(..))")
private void pointcutRest() { }
/*
//拦截restmapping注解
@Pointcut(value = "execution(@org.springframework.web.bind.annotation.RequestMapping public * com.tomato..*(..))")
private void pointCut() { } //拦截post注解
@Pointcut(value = "execution(@org.springframework.web.bind.annotation.PostMapping public * com.tomato..*(..))")
private void pointCutPost() { } //拦截get注解
@Pointcut(value = "execution(@org.springframework.web.bind.annotation.GetMapping public * *com.tomato..*(..))")
private void pointCutGet() { } //拦截Delete注解
@Pointcut(value = "execution(@org.springframework.web.bind.annotation.DeleteMapping public * com.tomato..*(..))")
private void pointCutDelete() { } //拦截put注解
@Pointcut(value = "execution(@org.springframework.web.bind.annotation.PutMapping public * com.tomato..*(..))")
private void pointCutPut() { }*/ @Pointcut("pointcutService()|| pointcutRest()")
private void pointcut() {
} @Around(value = "pointcut()")
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
String classAndMethodName = null;
Method currentMethod = null; try {
currentMethod = this.getCurrentMethod(pjp);
classAndMethodName = this.getCurrentCompleteMethodName(pjp);
} catch (Throwable e) {
log.error("初始化日志记录信息时出错", e);
return pjp.proceed();
} // 处理入参
this.processBefore(pjp, classAndMethodName); Object result = null;
try {
// 调用目标方法
result = pjp.proceed();
} catch (Throwable e) {
// 目标方法异常了
log.info("end执行方法:{}发生异常,异常简述:{}", classAndMethodName, e.getMessage());
throw e;
} // 处理返回值
processReturnValue(result, currentMethod, classAndMethodName); return result;
} /**
* 得到当前方法的对象引用
* @param pjp
* @return
* @throws NoSuchMethodException
* @throws SecurityException
*/
private Method getCurrentMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
MethodSignature mig = (MethodSignature) pjp.getSignature();
return pjp.getTarget().getClass().getMethod(mig.getName(), mig.getParameterTypes());
} /**
* 得到完整的方法名
* @param pjp
* @return
*/
private String getCurrentCompleteMethodName(ProceedingJoinPoint pjp) {
return pjp.getTarget().getClass() + "的" + pjp.getSignature().getName() + "方法";
} /**
* 处理入参打印
* @param pjp
* @param classAndMethodName
*/
private void processBefore(ProceedingJoinPoint pjp, String classAndMethodName) {
try {
if(null==pjp.getArgs() || pjp.getArgs().length==0) {
log.info("begin执行方法:{},方法无入参", classAndMethodName);
} else {
if(pjp.getArgs().length == 1) {
if (pjp.getArgs()[0] instanceof Serializable) {
if(isFile(pjp.getArgs()[0])) {
log.info("begin执行方法:{},入参为文件类型,文件名为:{}", classAndMethodName, getFileName(pjp.getArgs()[0]));
} else {
log.info("begin执行方法:{},入参为:{}", classAndMethodName, JSONObject.toJSONString(pjp.getArgs()[0]));
}
}
} else {
log.info("begin执行方法:{},有多个入参", classAndMethodName);
List<Object> list = Arrays.asList(pjp.getArgs());
final AtomicInteger index = new AtomicInteger(1);
list.stream().filter(x -> x instanceof Serializable).forEach(x -> {
if(isFile(x)) {
log.info("入参{}:{}", index.get(), getFileName(x));
} else {
log.info("入参{}:{}", index.get(), JSONObject.toJSONString(x));
}
index.incrementAndGet();
});
}
}
} catch (Throwable e) {
log.error("记录入参日志的时候出错:", e);
}
} /**
* 处理返回值
* @param result
* @param currentMethod
* @param classAndMethodName
*/
private void processReturnValue(Object result, Method currentMethod, String classAndMethodName) {
if(null == result) {
return;
}
try {
if(!currentMethod.isAnnotationPresent(NotPrintResponseLog.class) && result instanceof Serializable) {
log.info("end执行方法:{},返回结果:{}", classAndMethodName, JSONObject.toJSONString(result));
}
} catch (Throwable e) {
log.error("记录返回日志的时候出错:", e);
} } /**
* 获取文件上传的文件名
* @param file
* @return
*/
private String getFileName(Object file) {
return null==file ? "空文件" : ((MultipartFile)file).getName();
} /**
* 判断是否是文件类型
* @param obj
* @return
*/
private boolean isFile(Object obj) {
return obj instanceof MultipartFile;
}
}

20180530补充:

在aop的逻辑内,先走@Around注解的方法。然后是@Before注解的方法,然后这两个都通过了,走核心代码,核心代码走完,无论核心有没有返回值,都会走@After方法。然后如果程序无异常,正常返回就走@AfterReturn,有异常就走@AfterThrowing。

Aspect实现对方法日志的拦截记录的更多相关文章

  1. Apache 日志设置不记录指定文件类型的方法和日志轮

    Apache日志精准的记录了Web访问的记录,但对于访问量很大的站来说,日志文件过大对于分析和保存很不方便.可以在http.conf(或虚拟主机设置文件httpd-vhosts.conf)中进行设置, ...

  2. Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP

    回到目录 .Net MVC之所以发展的如些之好,一个很重要原因就是它公开了一组AOP的过滤器,即使用这些过滤器可以方便的拦截controller里的action,并注入我们自己的代码逻辑,向全局的异常 ...

  3. Spring Boot 使用 Aop 实现日志全局拦截

    前面的章节我们学习到 Spring Boot Log 日志使用教程 和 Spring Boot 异常处理与全局异常处理,本章我们结合 Aop 面向切面编程来实现全局拦截异常并记录日志. 在 Sprin ...

  4. Springboot 三种拦截Rest API的方法-过滤器、拦截器、切片

    过滤器方式实现拦截(Filter) 通过继承Servlet的Filter类来实现拦截: @Component public class TimeFilter implements Filter { @ ...

  5. tail -fn 1000 test.log | grep '关键字' 按照时间段 sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p' test.log /var/log/wtmp 该日志文件永久记录每个用户登录、注销及系统的启动、停机的事件

    Linux 6种日志查看方法,不会看日志会被鄙视的 2020-02-11阅读 7.3K0   作为一名后端程序员,和Linux打交道的地方很多,不会看Linux日志,非常容易受到来自同事和面试官的嘲讽 ...

  6. 30多条mysql数据库优化方法,千万级数据库记录查询轻松解决(转载)

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  7. SQLServer 2008以上误操作数据库恢复方法——日志尾部备份(转)

    问题: 经常看到有人误删数据,或者误操作,特别是update和delete的时候没有加where,然后就喊爹喊娘了.人非圣贤孰能无过,做错可以理解,但不能纵容,这个以后再说,现在先来解决问题. 遇到这 ...

  8. [转]SQLServer 2008以上误操作数据库恢复方法——日志尾部备份

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/8491327 问题: 经常看到有人误删数据,或者误操作,特别是update和delete的 ...

  9. SQL Server 2008以上误操作数据库恢复方法——日志尾部备份

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/8491327 问题: 经常看到有人误删数据,或者误操作,特别是update和delete的 ...

随机推荐

  1. 安装部署 Kubernetes 集群

    安装部署 Kubernetes 集群 阅读目录: 准备工作 部署 Master 管理节点 部署 Minion 工作节点 部署 Hello World 应用 安装 Dashboard 插件 安装 Hea ...

  2. JAVA开发中文乱码的几个解决方案

    一:html乱码或者引入的JS乱码 1:第一步,text file encoding 首先确保文件的保存格式要UTF-8,如在eclipse中,要在文件上点属性,确保这里选择UTF-8 注意,在ecl ...

  3. SVG 使用marker画箭头(一)

    一.使用Marker画箭头 1.定义一个箭头的marker引用 <defs> <marker id='markerArrow' markerWidth='13' markerHeig ...

  4. [转]小心PHP的类定义顺序与继承的问题

    FROM : http://www.pakey.net/blog/php-class-shunxu.html 以下代码的运行环境均为PHP5.3.11先来看一段代码 <?php class A  ...

  5. golang导入包的几个说明:import

    导入包: 标准包使用的是给定的短路径,如"fmt"."net/http" 自己的包,需要在工作目录(GOPATH)下指定一个目录,improt 导入包,实际上就 ...

  6. git如何上传所有的新文件 gitlab如何上传所有的新文件 git本地覆盖服务器 强制本地覆盖服务器

    原文地址:  https://blog.csdn.net/qq_28093585/article/details/78749153 目的描述:新建的git项目,项目中有许多要从本地上传到git仓库的新 ...

  7. NOIP2016 酱油记

    2016.11.17 考试前最后一个周四.然而我仍旧蒟蒻... 2016.11.18 周五,上午自家开车跑到晋城,中午12点到宾馆.下午4点去机房试机,先写了个线性筛,结果c++报错!?重开机,写个a ...

  8. CImg、libjpeg--介绍、配置(操作JPEG)

    关于处理图片,之前写了两篇博客关于ImageMagick的: <ImageMagick–介绍> <ImageMagick–VS2015环境配置.开发(registrykeylooku ...

  9. 推荐朋友 - LintCode

    拼多多笔试第三题 除了题目具体方法值得注意外,数据的输入格外注意 题目 描述 给n个人的朋友名单,告诉你user,请找出user最可能认识的人.(他和user有最多的共同好友且他不是user的朋友) ...

  10. Entity Framework 与 LINQ to SQL

    Entity Framework和LINQ to SQL到底有什么区别?这是一个很常见的问题.下面的表中简要罗列了两种技术的主要区别. LINQ to SQL Entity Framework 复杂度 ...