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

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. 第三方IDC性能测评主要指标

    弹性计算性能弹性计费模式就是 "即用即付 ",最小单位可以按小时来计算.随着云计算负载的增长,企业购买服务器带宽时的资源.   1.弹性计算性能   弹性计费模式就是"即 ...

  2. django的mysql设置和mysql服务器闲置时间设置

    服务器启动后,每个进程都会主动连接到mysql,要是长时间没有数据交互,mysql会自动断开连接. show variables like  '%timeout%'; 闲置连接的超时时间由wait_t ...

  3. cesium and three.js【转】

    https://blog.csdn.net/zhishiqu/article/details/79077883 这是威尔逊Muktar关于整合Three.js与铯的客人帖子.Three.js是一个轻量 ...

  4. MultipleRegularExpressionAttribute MVC中扩展自定义验证规则

    好久都没有写博客,最近工作中没有什么可写的,公司的项目是以业务为重,技术含量实在不咋的.这次sprint中有一个要求就是password必须一些规则,比如给你一些正则表达式必须满足几个,直接看效果吧 ...

  5. CSS-设置Footer始终在页面底部

    Footer顾名思义页脚,如果内容多的时候在底部时感官很好,但是当内容变少(无法撑开一屏的时候)footer不固定在底部,影响美观,对于已经从事前端工作的工作的来说应该是比价工作中入门级别的问题了,由 ...

  6. 添加PMD插件扫描潜在的bug

    上一节使用checkstyle来规范你的项目主要解决了代码编码规范问题,比如缩进换行等.这次继续代码健康工具类PMD. 什么是PMD PMD真的不像checkstyle这样的东西所见即所得啊,去官网找 ...

  7. 用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践

    https://zhuanlan.zhihu.com/p/25928551 近来在同时做一个应用深度学习解决淘宝商品的类目预测问题的项目,恰好硕士毕业时论文题目便是文本分类问题,趁此机会总结下文本分类 ...

  8. Android 与 js 简单互调

    总结: Android 调用  js: 在 Android 中创建通往 javascript 的接口; 在 html  中定义要执行的方法; 在  Android  中的具体事件中进行调用. cont ...

  9. libxml2的安装及使用[总结]

    1.前言 xml广泛应用于网络数据交换,配置文件.Web服务等等.近段时间项目中做一些配置文件,原来是用ini,现在改用xml.xml相对来说可视性更为直观,很容易看出数据之间的层次关系.关于xml的 ...

  10. MFC中调用web api

    使用COM组件来调用,需要catch com error. IXMLHTTPRequestPtr pIXMLHTTPRequest = NULL; BSTR bstrString = NULL; HR ...