Java 匹配接口注解的Spring AOP切入点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2847640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:35:06  来源:igfitidea点击:

Spring AOP pointcut that matches annotation on interface

javaspringaopaspectjpointcut

提问by Sean Patrick Floyd

I have a service class implemented in Java 6 / Spring 3 that needs an annotation to restrict access by role.

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

I have defined an annotation called RequiredPermission that has as its value attribute one or more values from an enum called OperationType:

我已经定义了一个名为 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
   }
}

I also have the following aspect definition:

我还有以下方面定义:

/**
 * 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());
    }
}

The parameter object contains a user name and I want to look up the required role for the user before allowing access to the method.

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

When I put the annotation on the method in MyServiceImpl, everything works just fine, the pointcut is matched and the aspect kicks in. However, I believe the annotation is part of the service contract and should be published with the interface in a separate API package. And obviously, I would not like to put the annotation on both service definition and implementation (DRY).

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

I know there are cases in Spring AOP where aspects are triggered by annotations one interface methods (e.g. Transactional). Is there a special syntax here or is it just plain impossible out of the box.

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

PS: I have not posted my spring config, as it seems to be working just fine. And no, those are neither my original class nor method names.

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

PPS: Actually, here is the relevant part of my spring config:

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

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

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

采纳答案by Espen

If I understand you correct, you want a pointcut that finds all methods in classes that extends MyService and is annotated and with the preferred arguments.

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

I propose that you replace:

我建议你更换:

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

with:

和:

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

The plus sign is used if you want a joinpoint to match the MyService class or a class that extends it.

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

I hope it helps!

我希望它有帮助!

回答by pkmk

Espen, your code works only for one class:

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

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

but what if I want this behaviour for all services in *com.mycompany.services.** package?

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