Pass method argument in Aspect of custom annotation

前端 未结 5 1990
说谎
说谎 2021-02-13 03:14

I\'m trying to use something similar to org.springframework.cache.annotation.Cacheable :

Custom annotation:

@Target(ElementType.METHOD)
             


        
5条回答
  •  囚心锁ツ
    2021-02-13 04:08

    Thanks to @StéphaneNicoll I managed to create a first version of a working solution:

    The Aspect

    @Component
    @Aspect
    public class CheckEntityAspect {
      protected final Log logger = LogFactory.getLog(getClass());
    
      private ExpressionEvaluator evaluator = new ExpressionEvaluator<>();
    
      @Before("execution(* *.*(..)) && @annotation(checkEntity)")
      public void checkEntity(JoinPoint joinPoint, CheckEntity checkEntity) {
        Long result = getValue(joinPoint, checkEntity.key());
        logger.info("result: " + result);
        System.out.println("running entity check: " + joinPoint.getSignature().getName());
      }
    
      private Long getValue(JoinPoint joinPoint, String condition) {
        return getValue(joinPoint.getTarget(), joinPoint.getArgs(),
                        joinPoint.getTarget().getClass(),
                        ((MethodSignature) joinPoint.getSignature()).getMethod(), condition);
      }
    
      private Long getValue(Object object, Object[] args, Class clazz, Method method, String condition) {
        if (args == null) {
          return null;
        }
        EvaluationContext evaluationContext = evaluator.createEvaluationContext(object, clazz, method, args);
        AnnotatedElementKey methodKey = new AnnotatedElementKey(method, clazz);
        return evaluator.condition(condition, methodKey, evaluationContext, Long.class);
      }
    }
    

    The Expression Evaluator

    public class ExpressionEvaluator extends CachedExpressionEvaluator {
    
      // shared param discoverer since it caches data internally
      private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
    
      private final Map conditionCache = new ConcurrentHashMap<>(64);
    
      private final Map targetMethodCache = new ConcurrentHashMap<>(64);
    
      /**
       * Create the suitable {@link EvaluationContext} for the specified event handling
       * on the specified method.
       */
      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);
      }
    
      /**
       * Specify if the condition defined by the specified expression matches.
       */
      public T condition(String conditionExpression, AnnotatedElementKey elementKey, EvaluationContext evalContext, Class 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;
      }
    }
    

    The Root Object

    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;
      }
    }
    

提交回复
热议问题