Springboot - AOP 中使用spel 表达式解析

Springboot - AOP 中使用spel 表达式解析


1、什么是SpEL

参考:

2、引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

3、开启AOP ,注册组件

/**
 * @author Created by 谭健 on 2019/11/4. 星期一. 10:39.
 * © All Rights Reserved.
 */

@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration {
}


@Aspect
@Slf4j
@Component
public class SpringElAop {
    
}

4、构建一个切入注解

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface SpelLog {


  String value() default "";


}

5、编写切面

import com.web.bottom.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
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.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

/**
 * @author Created by 谭健 on 2019/11/4. 星期一. 15:22.
 * © All Rights Reserved.
 */

@Aspect
@Slf4j
@Component
public class SpringElAop {


  private final Executor executor;

  public SpringElAop(Executor executor) {
    this.executor = executor;
  }

  @Pointcut("@annotation(com.web.framework.aop.SpelLog)")
  public void springElAop() {
  }


  @Around("springElAop()")
  public Object ar(ProceedingJoinPoint point) throws Throwable {

    MethodSignature signature = (MethodSignature) point.getSignature();
    Method signatureMethod = signature.getMethod();
    SpelLog spelLog = signatureMethod.getAnnotation(SpelLog.class);

    executor.execute(() -> {
      if (spelLog != null) {
        EvaluationContext context = getContext(point.getArgs(), signature.getMethod());
        String value = getValue(context, spelLog.value(), String.class);
        if (log.isInfoEnabled()) {
          log.info(" SpelLog {}", value);
        }
      }
    });

    return point.proceed();
  }


  /**
   * 获取spel 定义的参数值
   *
   * @param context 参数容器
   * @param key     key
   * @param clazz   需要返回的类型
   * @param <T>     返回泛型
   * @return 参数值
   */
  private <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 EvaluationContext getContext(Object[] arguments, Method signatureMethod) {

    String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(signatureMethod);
    if (parameterNames == null) {
      throw new BusinessException("参数列表不能为null");
    }

    EvaluationContext context = new StandardEvaluationContext();
    for (int i = 0; i < arguments.length; i++) {
      context.setVariable(parameterNames[i], arguments[i]);
    }
    return context;
  }


}


5、简单示例使用

@SpelLog("'会员'+#user.memberId+'从账本'+#user.accountId+'切换到'+#newAccountId")
public void changeDefaultAccount(Long newAccountId, User user) {
    
}

这样就可以愉快的使用参数值而不用写入到业务代码里面去了

发布了442 篇原创文章 · 获赞 1375 · 访问量 210万+

猜你喜欢

转载自blog.csdn.net/qq_15071263/article/details/102912189
今日推荐