使Spring Boot 自定义注解支持EL表达式

自定义注解

  • 自定义DistributeExceptionHandler注解,该注解接收一个参数attachmentId
  • 该注解用在方法上,使用该注解作为切点,实现标注该注解的方法抛异常后的统一处理。
/**
 * @Author: Lijian
 * @Date: 2019-09-06 09:26
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeExceptionHandler {
    String attachmentId();
}

  • 使用方法:
@DistributeExceptionHandler(attachmentId = "#test.id")
public void test(Test test){
    
}

Aspect代码

  • 拦截DistributeExceptionHandler注解作为切点
  • 使用@AfterThrowing处理异常情况
/**
 * @Author: Lijian
 * @Date: 2019-09-06 09:22
 */
@Component
@Aspect
@Slf4j
public class DistributeExceptionAspect {

    @Autowired
    private AttachmentContentClient attachmentContentClient;

    @Autowired
    private DistTaskService distTaskService;

    private ExpressionEvaluator<String> evaluator = new ExpressionEvaluator<>();

    @Pointcut("@annotation(DistributeExceptionHandler)")
    private void exceptionHandleMethod() {

    }

    @AfterThrowing(value = "exceptionHandleMethod()", throwing = "ex")
    public void doThrowing(JoinPoint joinPoint, Throwable ex) {
        log.error("捕获异常");
        String attachmentId = getAttachmentId(joinPoint); // 获取
        // 处理异常情况下的业务
    }

    private DistributeExceptionHandler getDistributeExceptionHandler(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getAnnotation(DistributeExceptionHandler.class);
    }

    private String getAttachmentId(JoinPoint joinPoint) {
        DistributeExceptionHandler handler = getDistributeExceptionHandler(joinPoint);
        if (joinPoint.getArgs() == null) {
            return null;
        }
        EvaluationContext evaluationContext = evaluator.createEvaluationContext(joinPoint.getTarget(), joinPoint.getTarget().getClass(), ((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getArgs());
        AnnotatedElementKey methodKey = new AnnotatedElementKey(((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getTarget().getClass());
        return evaluator.condition(handler.attachmentId(), methodKey, evaluationContext, String.class);
    }
}

为注解添加Spring EL支持

  • ExpressionRootObject
/**
 * @Author: Lijian
 * @Date: 2019-09-06 09:26
 */
public class ExpressionRootObject {
    private final Object object;
    private final Object[] args;

    public ExpressionRootObject(Object object, Object[] args) {
        this.object = object;
        this.args = args;
    }

    public Object getObject() {
        return object;
    }

    public Object[] getArgs() {
        return args;
    }
}

  • ExpressionEvaluator

/**
 * @Author: Lijian
 * @Date: 2019-09-06 09:26
 */
public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
    private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
    private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
    private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);


    public EvaluationContext createEvaluationContext(Object object, Class<?> targetClass, Method method, Object[] args) {
        Method targetMethod = getTargetMethod(targetClass, method);
        ExpressionRootObject root = new ExpressionRootObject(object, args);
        return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
    }


    public T condition(String conditionExpression, AnnotatedElementKey elementKey, EvaluationContext evalContext, Class<T> clazz) {
        return getExpression(this.conditionCache, elementKey, conditionExpression).getValue(evalContext, clazz);
    }

    private Method getTargetMethod(Class<?> targetClass, Method method) {
        AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
        Method targetMethod = this.targetMethodCache.get(methodKey);
        if (targetMethod == null) {
            targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
            if (targetMethod == null) {
                targetMethod = method;
            }
            this.targetMethodCache.put(methodKey, targetMethod);
        }
        return targetMethod;
    }
}

备注

  • 本文参考:*
上一篇:获取设备树中GPIO的第三个参数


下一篇:Datawhale cv 目标检测笔记 day2