Spring Boot结合自定义注解实现日志记录
有业务场景需要记录调用方法的操作日志,打算使用注解加切面的方式实现,此处先做个测试Demo
1.定义操作日志注解@Log
@Retention 表示这是一个运行时注解,即运行起来之后,才获取注解中的相关信息,而不像基本注解@Override 那种不用运行,在编译时eclipse就可以进行相关工作的编译时注解。
@Target指定注解的类型 可以是方法、属性等,取值(ElementType)有:
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述符
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER: 用于描述参数
- TYPE: 用于描述类、接口(包括注解类型)或者enum声明
package com.huida.investment; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Date; /** * 自定义操作日志注解 * @Author zhanghailang * @Date 2020/10/16 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { //操作员 String operator() default "其他"; //保全类型 String edortype() default "其他"; // Date edorAppDate() default new Date("111111") ; //保全阶段 String state(); }
2.定义切面类 注解配合切面使用是一种很常见的做法,也可以使用过滤器的方式,本次只记录切面的方法,过滤器的后以后有时间再整理。。
package com.huida.investment; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.AfterReturning; 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 sun.rmi.runtime.NewThreadAction; import java.lang.reflect.Method; /** * 操作日志切面处理 * @Author zhanghailang * @Date 2020/10/16 */ @Aspect//表明这是一个切面类 @Component public class LogAspect { /** * pointcut表示这是一个切点,@annotation表示这个切点切到一个注解上,后面带该注解的全类名 */ @Pointcut("@annotation(com.huida.investment.Log)") public void logPointCut(){}; /** * 环绕通知 */ @AfterReturning("logPointCut()") public void logArround(JoinPoint joinPoint){ //获取方法名称 String methodName = joinPoint.getSignature().getName(); //获取入参 Object[] params = joinPoint.getArgs(); StringBuilder builder = new StringBuilder(); for (Object o : params){ builder.append(o + ";"); } System.out.println("进入方法["+methodName+"],,,参数为:" + builder.toString()); //获得注解 Log testlog = getAnnotationLog(joinPoint); getControllerMethodDescription(testlog); System.out.println(methodName + "方法执行结束"); } /** * 是否存在注解,存在就获取 * @param joinPoint * @return */ private Log getAnnotationLog(JoinPoint joinPoint){ Signature signature =joinPoint.getSignature(); MethodSignature methodSignature =(MethodSignature)signature; Method method =methodSignature.getMethod(); if (method != null){ return method.getAnnotation(Log.class); } return null; } /** * 获取注解中对方法的描述信息 注解Log中的各个参数 * @param testlog */ private void getControllerMethodDescription(Log testlog){ //此处仅用来测试用,实际操作过程中,可能会有日志插表等逻辑 String operator = testlog.operator(); String state = testlog.state(); System.out.println("注解在方法内的参数 operator : " + operator + ", state :" + state); } }
3.测试使用
package com.huida.investment; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * @description: 日志注解测试类 * @author: zhanghailang * @date: 2020-10-16 15:33 */ @RestController public class TestLogController { @Log(state = "测试日志注解") @GetMapping("/testLog/{username}") public String testLog(@PathVariable("username") String username){ return "测试成功"; } }
4.运行效果
zhanghailang
解释
@Documented:注解信息会被添加到Java文档中
@Retention:注解的生命周期,表示注解会被保留到什么阶段,可以选择编译阶段、类加载阶段,或运行阶段
@Target:注解作用的位置,ElementType.METHOD表示该注解仅能作用于方法上
@Interface 注明这是一个自定义注解
@Pointcut("@annotation(com.huida.investment.Log)")表示用到Log注解的地方作为aop的连接点
参考文章
自定义注解实现操作日志 https://blog.csdn.net/zhanghailang1/article/details/109119858
spring之自定义注解 https://blog.csdn.net/weixin_37598682/article/details/81542235
Spring AOP - 注解方式使用介绍(长文详解)https://segmentfault.com/a/1190000020904086?utm_source=tag-newest
学习心得
软件工程师就是搬砖的民工,根据软件步骤一步一步搭建环境,然后结合自己的业务需求实现简单的逻辑即可。大部分时间都浪费在搭建环境上,搭建环境也不能算是知识点。大多数软件框架都是国外的,英语书写,对于中国人来说看不懂英文,环境搭建也有了门槛。希望以后多出现中国人写的框架,那么软件环境的搭建就一定会轻而易举。