Spring AOP和Spring Boot - 代理已创建,但建议未执行

时间:2015-11-30 14:41:38

标签: java spring-boot aspectj spring-aop

我现在已经浏览了网络和堆栈溢出数小时,而我似乎无法找到问题的解决方案。我的猜测是,对于那些比我更熟练的AOP来说,它是微不足道的,但是显而易见。

我们正在为我们的应用程序使用Spring Boot 1.2.6.RELEASE,我希望包含一个名为@Prohibited的自定义注释,以便能够根据用户的权限执行@Around建议设置和注释的值。

到目前为止,我只有一个空白注释,我希望我的建议可以围绕任何使用@Prohibited注释的方法执行。

注释:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Prohibited {
}

方面:

@Aspect
@Component
public class PermissionAspect {

    @Pointcut("execution(@com.whatever.commons.logic.permission.Prohibited * *(..))")
    public void prohibited() {}

    @Around("prohibited()")
    public Object permit(final ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("########### - " + joinPoint.getSignature().getName());
        joinPoint.proceed();
        return null;
    }
}

带注释的方法:

@Component
public class AnyService {

    @Prohibited
    public List<Object> anyMethod() {
        //anything - assume a breakpoint here
    }
}

在我的pom.xml中,我包含了spring-boot-starter-aop依赖项:

<!-- spring boot with aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

最后在application.properties文件中,我添加了以下行,以便使Spring能够围绕类创建代理,而不仅仅是接口:

spring.aop.proxy-target-class=true

现在我设置了一个断点到注释方法的第一行,并期望至少看到我在控制台中的建议打印出来,但它永远不会发生。

相反,应用程序在断点处挂起而不打印任何行。有趣的是,我可以在调用堆栈中看到确实为类创建了代理,我可以看到如下内容:

CglibAopProxy$CglibMethodInvocation.invokeJoinpoint() line: 717
CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 157

如果我注释掉@Prohibited注释,根本就没有生成代理,所以看起来Spring确实在我指定的类周围创建了一个CGLIB代理(显然是由于我方面定义的@Pointcut),但它确实不执行我的@Around建议,而只是进入连接点。

有谁知道我在这里缺少什么?我是否应该使用编译时编织(如果可能的话,我想避免这种情况)?

*更新*

我忘了提到的是如何实际调用该方法。从另一个服务(在这种情况下也称为控制器):

@RestController
public class AnyController {

    @Autowired
    AnyService anyService;

    @RequestMapping("/this/that")
    public ResponseEntity<Object> something() {
        this.anyService.anyMethod();
    }
}

问题是我注释了错误的方法(见下面的答案)。

1 个答案:

答案 0 :(得分:1)

我明白了。我知道这很小,可能很傻。

在修改编译时编织后,我注意到我注释了错误的方法。我的服务有两个公共方法,而一个是调用另一个(毕竟可能不是一个好的设计),如下所示:

@Component
public class AnyService {

    public Object firstMethod() {
        //doing stuff...
        this.secondMethod();
    }

    @Prohibited
    public Object secondMethod() {
        //here be breakpoint
    }
}

因此,当断点命中时,我已经超出了代理,并且由于没有注释第一个方法,因此没有执行方面。

自我注意:方法调用必须来自服务外部,否则将无法通知代理。

我希望这会帮助某人遇到同样的问题。