SpEl 实现自定义日志记录

在前面我们介绍了SpEl(Spring Expression Language)解析与Spring SpEl高级语法,但是SpEl在时间的开发中能帮助我们做些什么呢?该如何与自己的业务进行匹配呢?本讲将介绍一种使用方式,Aop + SpEl实现日志记录!主要是通过SpEl实现自定义的记录.Aop大家应该都很熟悉,这里不做过多介绍,如果不是很了解,可以先阅读Spring Aop 核心概念 ,下面我将进行核心的业务开发。
自定义注解
我们将自定义一个注解,用与拦截
(ElementType.METHOD)(RetentionPolicy.RUNTIME)public DemoLog {String name() default "demo";String el();}
Aop 实现
这里我们采用@Around的方式,在方法前进行监听,与发生异常时进行监听
4jpublic class LogAspect {(value = "@annotation(DemoLog)")public void logAspect() {}/*** 环绕处理** @param joinPoint* @throws Throwable*/(value = "logAspect()")public Object getAroundLog(ProceedingJoinPoint joinPoint) throws Throwable {Object proceed;try {//前置处理saveLogAspect(joinPoint, null);proceed = joinPoint.proceed();return proceed;} catch (Throwable throwable) {saveLogAspect(joinPoint, throwable);throw new RuntimeException(throwable.getMessage());}}private void saveLogAspect(JoinPoint joinPoint, Throwable throwable) {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();try {// 获取自定义注解DemoLog demoLog = methodSignature.getMethod().getAnnotation(DemoLog.class);if (Objects.nonNull(demoLog)) {Object spEl = AspectExpress.getSpEl(joinPoint, methodSignature, demoLog.el(), Object.class);if (log.isInfoEnabled()) {log.info(" SpelLog {}", spEl);}}} catch (Exception e) {log.error(e.getMessage());}}}
自定义 SpEl解析器
我们通过自定义SpEL解析的方式实现
public class AspectExpress {public static <T> T getSpEl(JoinPoint joinPoint, MethodSignature methodSignature, String el, Class<T> clazz){EvaluationContext context = getContext(joinPoint.getArgs(), methodSignature.getMethod());return getValue(context, el, clazz);}/*** 获取spel 定义的参数值** @param context 参数容器* @param key key* @param clazz 需要返回的类型* @param <T> 返回泛型* @return 参数值*/private static <T> T getValue(EvaluationContext context, String key, Class<T> clazz) {SpelExpressionParser spelExpressionParser = new SpelExpressionParser();Expression expression = spelExpressionParser.parseExpression(key);return expression.getValue(context, clazz);}/*** 获取参数容器** @param arguments 方法的参数列表* @param signatureMethod 被执行的方法体* @return 装载参数的容器*/private static EvaluationContext getContext(Object[] arguments, Method signatureMethod) {String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(signatureMethod);if (parameterNames == null) {throw new RuntimeException("参数列表不能为null");}EvaluationContext context = new StandardEvaluationContext();for (int i = 0; i < arguments.length; i++) {context.setVariable(parameterNames[i], arguments[i]);}return context;}}
使用方式
public class SpElDemo {public void get( Integer id){}public void get(SecurityProperties.User user){}}

加上以SpEl的功能可以让我们的Aop操作更加强大。也可以实现更多的处理,可以是我们的日志更加丰富
评论
