【问题标题】:Spring AOP pointcut that matches annotation on interface与接口上的注释匹配的 Spring AOP 切入点
【发布时间】:2011-02-20 07:36:12
【问题描述】:

我有一个用 Java 6 / Spring 3 实现的服务类,它需要一个注释来限制角色的访问。

我定义了一个名为RequiredPermission 的注释,它的值属性是一个或多个来自名为OperationType 的枚举的值:

public @interface RequiredPermission {

/**
 * One or more {@link OperationType}s that map to the permissions required
 * to execute this method.
 * 
 * @return
 */
OperationType[] value();}

public enum OperationType {
      TYPE1,
      TYPE2;
}

package com.mycompany.myservice;
public interface MyService{
   @RequiredPermission(OperationType.TYPE1)
   void myMethod( MyParameterObject obj );
}

package com.mycompany.myserviceimpl;
public class MyServiceImpl implements MyService{
   public myMethod( MyParameterObject obj ){
       // do stuff here
   }
}

我还有以下方面的定义:

/**
 * Security advice around methods that are annotated with
 * {@link RequiredPermission}.
 * 
 * @param pjp
 * @param param
 * @param requiredPermission
 * @return
 * @throws Throwable
 */
@Around(value = "execution(public *"
        + " com.mycompany.myserviceimpl.*(..))"
        + " && args(param)" + // parameter object
        " && @annotation( requiredPermission )" // permission annotation

, argNames = "param,requiredPermission")
public Object processRequest(final ProceedingJoinPoint pjp,
        final MyParameterObject param,
        final RequiredPermission requiredPermission) throws Throwable {
    if(userService.userHasRoles(param.getUsername(),requiredPermission.values()){
        return pjp.proceed();
    }else{
        throw new SorryButYouAreNotAllowedToDoThatException(
            param.getUsername(),requiredPermission.value());
    }
}

参数对象包含一个用户名,我想在允许访问该方法之前查找用户所需的角色。

当我将注解放在 MyServiceImpl 中的方法上时,一切正常,切入点匹配并且切面启动。但是,我相信注解是服务合同的一部分,应该与接口一起发布在单独的 API 包。显然,我不想在服务定义和实现 (DRY) 上都添加注释。

我知道在 Spring AOP 中有些情况是由注释一个接口方法(例如事务)触发方面的。这里有什么特殊的语法,还是开箱即用是不可能的。

PS:我没有发布我的 spring 配置,因为它似乎工作得很好。不,这些既不是我原来的类名也不是方法名。

PPS:实际上,这是我的 spring 配置的相关部分:

<aop:aspectj-autoproxy proxy-target-class="false" />

<bean class="com.mycompany.aspect.MyAspect">
    <property name="userService" ref="userService" />
</bean>

【问题讨论】:

  • 所以,如果我理解正确,您为原始问题找到的最佳解决方案(即,在接口中而不是在实现中)是匹配整个服务提供者接口包,然后反省 ProceedingJoinPoint 以便找出接口中方法的注解?这甚至可能吗?这是一个很棒的话题,不想用同样的问题开始一个新的话题!谢谢!!
  • @espinchi 实际上我非常沮丧,以至于我将所有注释从接口复制到实现类,并通过严格的单元测试来强制执行该测试,该测试检查接口和实现类上的所有方法是否具有相同的注释。我知道,不完全是 AOP。毕竟,我会说它不能可靠地工作

标签: java spring aop aspectj pointcut


【解决方案1】:

如果我的理解正确,您需要一个切入点,该切入点可以找到扩展 MyService 并带有注释并带有首选参数的类中的所有方法。

我建议你替换:

execution(public * com.mycompany.myserviceimpl.*(..))

与:

execution(public * com.mycompany.myservice.MyService+.*(..))

如果您希望连接点与 MyService 类或扩展它的类匹配,则使用加号。

希望对你有帮助!

【讨论】:

  • 有一个小错字。它实际上是: execution(public * com.mycompany.myservice.MyService+.*(..)) 但它就像一个魅力。非常感谢!!!
  • 太好了!我将更正我的答案,以便在所有方法中也包含通配符。
  • 我后来意识到这并不完全正确(尽管这可能是最好的选择)。我希望注释位于服务接口方法上,但这仅在注释位于实现方法上时才有效。而且由于我也需要这种行为:stackoverflow.com/questions/3100228/…,所以我必须保持最小切入点并自己检查procedureingjoinpoint对象。
【解决方案2】:

Espen,您的代码仅适用于一类:

execution(public * com.mycompany.myservice.MyService+.*(..))

但是如果我希望 *com.mycompany.services.** 包中的所有服务都具有这种行为呢?

【讨论】:

  • 这很好用:execution(public * com.mycompany.myservice.*+.*(..))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多