代码之家  ›  专栏  ›  技术社区  ›  Michal Milicua

springaop方面与Spring数据仓库的切入点行为不一致

  •  0
  • Michal Milicua  · 技术社区  · 6 年前

    上下文

    我使用AOP通过拦截Spring数据存储库的save和delete方法来创建/删除托管实体的springacl记录。我所有的存储库都是 @RepositoryRestResource 带注释的接口扩展 PagingAndSortingRepository CrudRepository . 这在过去一直很有效。不幸的是,我无法确定它停止工作的时间点(或代码更改)。

    预期行为

    以下建议应针对所有保存方法激发。

    @Pointcut("execution(* org.springframework.data.repository.*.save(*))")
    public void defaultRepoSave() {}
    
    // may be useful for overridden methods
    @Pointcut("execution(* com.xxx.yyy.repository.*.save(..))")
    public static void customRepoSave() {}
    
    @Pointcut("defaultRepoSave() || customRepoSave()")
    public static void repoSave() {}
    
    @Around(value="repoSave() && args(entity)", argNames="entity")
    public Object aroundSave(ProceedingJoinPoint pjp, Object entity) throws Throwable{
        log.info("Saving ...");
        return pjp.proceed();
    }
    

    注:我试过各种组合 @EnableAspectJAutoProxy(exposeProxy=true/false, proxyTargetClass=true/false)

    问题

    这些建议针对某些存储库,而不是其他存储库。两个存储库在同一个包中。调试表明这两个存储库都是代理的,但是对左边的存储库的执行完全缺少与通知相关的拦截器。右边的那个按预期进行。

    Screenshot

    为了消除切入点不匹配的可能性,我创建了一个自定义注释,并将其添加到两个存储库中的.save()方法中。

    注释:

    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface AclManaged {}
    

    用作:

    @Override
    @AclManaged
    Entity1 save(Entity1 entity); 
    

    建议是:

    @Around("@annotation(aclManaged)")
    public Object aclManaged(ProceedingJoinPoint joinPoint, AclManaged aclManaged) throws Throwable {
        log.info("Acl managed");
        return joinPoint.proceed();
    }
    

    相同的故事-注释可以在一个存储库中工作,但是对于存储库,如果 execution(..save..)

    出于测试目的,我通过从Postman向每个存储库rest端点发布一个空实体来调用这两个方法。但是,当直接从我的代码调用存储库时,也会发生同样的问题。

    ---编辑:我将存储库简化到最低限度---

    @RepositoryRestResource(collectionResourceRel = "entity1s", path = "entity1s")
    public interface Entity1Repository extends PagingAndSortingRepository<Entity1, Long> {
    
        // this is the method that is supposed to fire two distinct advices
        @Override
        @AclManaged
        Entity1 save(Entity1 entity);
    }
    
    @RepositoryRestResource(collectionResourceRel = "entity2s", path = "entity2s")
    public interface Entity2Repository extends PagingAndSortingRepository<Entity2, Long> {
    
    
        // both aspects match perfectly
        @Override
        @AclManaged
        Entity2 save(Entity2 ics);
    
    
    }
    

    问题

    解决AOP方面问题的最佳方法是什么?(如果执行和注释切入点都失败)

    版本

    spring5.0.8.RELEASE,springdatarest3.0.9.RELEASE,springdatajpa2.0.9.RELEASE(全部由springboot2.0.4管理)

    1 回复  |  直到 6 年前
        1
  •  0
  •   Michal Milicua    6 年前

    这个问题似乎是由SpringBoot的不幸组合引起的 @Enable... @Configuration 类。框架似乎有几种不同的方法来确定类/接口代理(源于 @EnableCaching , @EnableTransactionManagement @EnableAspectJAutoProxy , @EnableAsync

    • 添加 proxyTargetClass=true 对所有人 @Enable..
    • 移动 相关注释 班级

    我仍然有兴趣深入了解不一致的MethodInvocationInterceptor链背后的根源。