spring AoP,具有相同参数类型的重载方法的切入点表达式

时间:2014-11-12 05:46:00

标签: spring aop spring-aop pointcut pointcuts

我已经在评论中为CRUD操作定义了一个类。 read方法过载了。

class Comment{
    // method 1: returns all the comments by a user
    findAll(long userId, long subjectId, String param);

    // method 2: returns all the comments of all the users
    findAll(long subjectId, String param)
}

我试过的切入点表达式是

@Around("execution(* com.package..*Controller.findAll(..)) && args(userId,subjectId,..)")
public Object validateFindAll(final ProceedingJoinPoint proceedingJoinPoint, final long userId, final long subjectId) {
    // validate userId, if available
    // validate subjectId
}

问题:由于userId和subjectId的数据类型相同,因此应用于方法2时的点表达式会将参数值移动1位。这意味着,表达式不理解第一个参数userId未被传递。相反,userId得到了#subject; subjectId'作为值,subjectId得到相邻的参数' param'作为它的价值。

注意

  1. 我试图避免编写另一种方法,如findUserComments()。

  2. 我想在整个应用程序中保持一致性。还有其他类具有类似的CRUD操作模式。

  3. 问题:是否可以定义适用于两个方法的表达式,第一个参数userId是可选的?

    编辑 - 解决方案 当我在下面的解决方案中提出不同的方法时,我终于删除了方法2.我在方法1中处理了这种情况。

2 个答案:

答案 0 :(得分:2)

您无法显式绑定AspectJ参数,然后希望它与不兼容的签名匹配。因此,您的切入点仅匹配findAll(long, long, ..),即"方法1"在你的例子中。您可以使用..指定可选参数,但不能将它们绑定到命名参数。

例如,可以匹配两种方法并通过long subjectId绑定String paramargs(.., subjectId, param),因为这两个参数在签名末尾可以预测为右对齐。如果您需要任何可选(因此未绑定)参数,则需要使用thisJoinPoint.getArgs()

@Around("execution(* com.package..*Controller.findAll(..)) && args(.., subjectId, param)")
public Object validateFindAll(
    final ProceedingJoinPoint thisJoinPoint,
    final long subjectId,
    final String param
) {
    if (thisJoinPoint.getArgs().length == 3)
        System.out.println(thisJoinPoint + " -> " + thisJoinPoint.getArgs()[0] + ", " + subjectId + ", " + param);
    else
        System.out.println(thisJoinPoint + " -> " + subjectId + ", " + param);
    // (...)
}

但是getArgs()是动态的,它可能比参数绑定慢,因为它使用反射。也许有两个切入点并不是那么糟糕。如果你的建议方法在proceed()之前/之后做了复杂的事情,你仍然可以将这些事情考虑在辅助方法中并从两个建议中调用它们。

答案 1 :(得分:0)

问题实际上与方法有关。因为,你传递的是long userId和long subjectId,AOP总是会尝试匹配这些参数。解决方案可能是

1)为其他参数创建另一个切入点,例如1表示long,long,其他表示long,String

2)在开头使用变量参数签名,例如

 @Around("execution(* com.org..findAll(..)) && args(..,subjectId,param)")
public Object validateFindAll(final ProceedingJoinPoint joinPoint, final long userId, final long subjectId) {

 }

而不是在开头使用变量参数。然后你可以使用getArgs()方法来计算参数。 这是一个简单的解决方案,但可能会减慢您的处理速度。

3)虽然作为一个设计问题,我建议将所有参数封装在一个对象中并传递它。而不是传递多个参数。它也将在未来帮助你。