自定义注解+AOP,优雅的打印方法接受和返回的参数内容
Posted 默辨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义注解+AOP,优雅的打印方法接受和返回的参数内容相关的知识,希望对你有一定的参考价值。
写在前面
经历了近两个月的时间,我终于完成了一个项目点十多个接口的开发到现场SIT。在这个过程中我深刻的意识到了添加日志的重要性(以前的自己从来不会想着添加日志,这次是真的给我上了一课)。
举一个授信占用接口的例子。在我们的系统中,前台对一笔交易进行提交审批的时候,最终会通过一个接口发送对应的数据给与之对应的信贷系统(两个系统的交互,其实还有涉及中转平台)。在调用授信接口前,我统会对那一笔业务进行相应的授信数据处理(业务流程也十分复杂),最终会把接口需要的参数(对方信贷系统需要的参数)添加到指定的对象中,然后接口再组装成指定格式的报文数据,发送给对方。
在这个过程中有一个问题,我如何能够确保我接受到的参数是正确的?即当我按照对方信贷系统需要的参数去对象中get值得时候,拿到了null,我如何去定位是因为前台授信处理后给我传的对象中的值为null(授信后没有传),还是我拿到值以后,由于我进行了相关的逻辑操作导致变成了null?
授信开发人员往往会在调用相关接口的地方,将发送给的对象打印到日志中,以便于日中定位是他们传值的问题还是接口这边的逻辑问题。
只能说这个解决办法是,授信功能的开发人员定位问题的方法,但现场出现了生产问题,第一个找的人却往往是接口的开发人员(我就被找了几次),此时我由于不了解授信相关的业务逻辑,更不可能知道他们会在什么地方打印传给接口的对象,所以我需要自己去对接受到的参数对象进行打印。
可这人呀,总是会忘记,只有每次出现了问题,我才会想到,为什么我最开始没有在这个位置打印一下结果呢?
总结一句话:我要打印方法传入的参数的内容
我能想到的打印方式有三种,有其他更好的方法,欢迎评论给出
第一种打印方式
在方法开始的位置,直接调用相关的log.info(xxx)方法
1、定义一个logger变量
private static Logger logger = LoggerFactory.getLogger(xxx.class);
2、指定位置打印参数
logger.info("xxxx");
第二种打印方式
直接抽取为一个公共方法
1、将传入当前类这个步骤放到工具类中
public static void logInfo(Class<?> clazz,Throwable e)
LoggerFactory.getLogger(clazz).info(e.getMessage(),e);
2、每个方法内直接调用
LogUtils.logInfo(this.getClass(),"xxxx");
第三种打印方式
有感于前面的方式太麻烦,且不好看,我想到的一个解决方法。使用时仅需要在类上添加一个@Log注解即可,但是该注解仅能打印接受和返回的对象,对于业务中的日志打印目前是没有办法完成,解析对象是利用的Gson(我甚至想过使用一个模板方法,对应的解析过程给一个扩展接口,自己想修改就重写对应的方法,但想想算了,后期有需要再说)
目前该注解的功能为:
- 打印方法接受到的对象的值,使用时只需要添加对应的前缀字符串即可定位日志记录
- 可以选择是否打印返回对象
我使用了一个try catch包裹我的代码,并且catch中并未抛出异常,仅仅是添加了一个error的日志记录。原因是因为我怕接受到的参数解析会出现异常,以至于影响了原本正常的业务流程
1、自定义一个Log注解
@Target(ElementType.PARAMETER, ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
// 日志前的标记
String[] logPreArr();
// 是否需要打印返回对象
boolean isNeedReturn() default false;
2、利用Spring的AOP,编写相关的切入方法
@Aspect
@Component
public class LogAspect
// 配置织入点
@Pointcut("@annotation(pers.mobian.logannotation.annotation.Log)")
public void logPointCut()
@Before("logPointCut() ")
public void beforeLog(JoinPoint point) throws Exception
// 1、目标类
Class<?> aClass = point.getTarget().getClass();
Logger log = LoggerFactory.getLogger(aClass);
try
// 2、目标方法
Log logAnno = getAnnotationLogByPoint(point);
if (logAnno != null)
// 3、打印目标参数
Object[] args = point.getArgs();
Gson gson = new Gson();
String[] value = logAnno.logPreArr();
if (value.length == 1)
for (Object arg : args)
log.info(point.getSignature().getName() + "方法:" + value[0] + ":" + gson.toJson(arg));
else if (value.length == args.length)
for (int i = 0; i < args.length; i++)
log.info(point.getSignature().getName() + "方法:" + value[i] + ":" + gson.toJson(args[i]));
else
log.info(point.getSignature().getName() + "方法:" + "参数类型与Log注解指定个数不匹配" + gson.toJson(args));
catch (Exception e)
log.error(point.getSignature().getName() + "方法:Log注解解析出现异常:" + e.getMessage());
@AfterReturning(pointcut = "logPointCut() ", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) throws Exception
Class<?> aClass = joinPoint.getTarget().getClass();
Logger log = LoggerFactory.getLogger(aClass);
try
Log logAnno = getAnnotationLogByPoint(joinPoint);
if (logAnno != null)
boolean needReturn = logAnno.isNeedReturn();
if (needReturn)
log.info(joinPoint.getSignature().getName() + "方法:" + "返回结果:" + jsonResult);
catch (Exception e)
log.error(joinPoint.getSignature().getName() + "方法:Log注解解析出现异常:" + e.getMessage());
private Log getAnnotationLogByPoint(JoinPoint joinPoint) throws Exception
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
return method.getAnnotation(Log.class);
return null;
3、编写的测试方法
@Log(logPreArr = "测试方法4",isNeedReturn = true)
public Map<String, Object> show4(Teacher student)
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("第一个",1);
dataMap.put("第二个","2");
dataMap.put("第三个",true);
dataMap.put("第四个",student);
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("第一个",1);
returnMap.put("第二个","2");
returnMap.put("第三个",true);
returnMap.put("第四个",student);
returnMap.put("第五个",dataMap);
return returnMap;
@Log(logPreArr = "接受到的老师实体类", "接收到的学生实体类")
public String show5(Teacher teacher, Student student)
return student.toString();
打印结果:
以上是关于自定义注解+AOP,优雅的打印方法接受和返回的参数内容的主要内容,如果未能解决你的问题,请参考以下文章