背景
在原有项目基础上,增加一个记录用户操作日志的功能。如用户的新增、修改、删除操作,都需要记录到日志中,方便日后分析使用。
要实现这个功能最简单的解决方式就是直接在需要记录日志的地方调用OperateLogService.add()
方法,但是这种做法会让代码中嵌入过多与实际业务无关的代码,且各个需要记录日志的地方都需要改动其原有代码,无论是代码的重复利用率还是耦合程度,都不建议如此做。
那么为了优雅的实现日志功能,我们最终选择利用SpringAOP+自定义注解+SpEL表达式来完成。
实现
自定义注解
自定义一个用于标注操作日志的注解:
其中OperateType
是个枚举型,用于表示操作类型:
在需要记录操作日志的方法上面加上这个注解,如:
SpringAOP & SpEL表达式解析
Spring支持在配置文件中配置切面层,也可以自定义标有Aspect注解的类来实现AOP。本例中我们采用后者来实现。
说明:
- 本例以标记了
@OperateLog
注解的方法为切入点,在方法执行之前,织入增强before
方法,将操作记录添加到数据库中。 - 私有方法
parseSpel
用于解析SpEL表达式。自定义注解的desc字段支持SpEL表达式,可通过类似前面的DemoService.addDemo(Demo demo)
方法注解上的desc传入的#demo.name
来获取入参中的值。因此,在解析SpEL表达式之前,需要将请求入参作为自定义变量设置到上下文环境中,SpEL解析器会在解析后从上下文环境中获取对应的值。 - 获取方法的参数名列表可以通过反射+javassist库的方式获取,不过本例中使用的是Spring提供的
LocalVariableTableParameterNameDiscoverer
,它是Spring基于ASM框架实现的,相比javassist使用起来会简单许多。
启动Spring对@Aspect注解的支持
最后一步,不要忘记在Spring的配置文件中启动对@Aspect注解的支持
注意:
OperateLogAspect
是标记了@Component注解的组件,Spring扫包时,需要注意是否在其扫包范围内。