当前位置: 首页 > 知识库问答 >
问题:

如何检测/建议Spring Data(JPA)存储库?

施德元
2023-03-14

我为spring数据jpa存储库提供建议的努力失败了。目标是(围绕)使用自定义注释(本例中的ResourceNotFound)注释的特定存储库中的所有非void公共方法,并在返回值为null或空集合时引发异常。

@Repository 
@ResourceNotFound
@Transactional(readOnly = true)
public interface CityRepository extends JpaRepository<City, Long>, JpaSpecificationExecutor<City> { … }

下面的建议是连接使用@ResourceNotFound注释的接口实现的所有公共方法。

@Pointcut("within(com.digitalmisfits.spring.aop.annotation.ResourceNotFound *)")
public void beanAnnotatedWithResourceNotFound() {}

@Pointcut("execution(public * *(..))")
public void publicMethod() {}

@Around("beanAnnotatedWithResourceNotFound() && publicMethod()")
public Object publicMethodInsideAClassMarkedWithResourceNotFound(ProceedingJoinPoint pjp) throws Throwable {

    System.out.println("publicMethodInsideAClassMarkedWithResourceNotFound " + pjp.getTarget().toString());;

    Object retVal =  pjp.proceed();

    if(((MethodSignature) pjp.getSignature()).getReturnType() != Void.TYPE && isObjectEmpty(retVal))
        throw new RuntimeException("isObjectEmpty == true");

    return retVal;
}

当切入点指定为以下内容时,publicMethodInsideAClassMarkedWithResourceNotFound(…)方法有效:

@Pointcut("execution(public * package.CityRepository+.*(..))")

但是,未提取ResourceNotFound注释。这可能是因为存储库接口的底层类是一个(代理的)SimpleJPrepository,它没有特定的注释。

有没有一种方法可以将@ResourceNotes传播到实现中?

--更新--

更改了问题以反映这样一个事实,即建议(around)只应适用于具有自定义注释的存储库。

共有3个答案

弓泰
2023-03-14

我能够使用以下构造解决我的问题(基本上检查接口链并搜索特定注释):

@Pointcut("execution(public !void org.springframework.data.repository.Repository+.*(..))")
public void publicNonVoidRepositoryMethod() {}

@Around("publicNonVoidRepositoryMethod()")
public Object publicNonVoidRepositoryMethod(ProceedingJoinPoint pjp) throws Throwable {

    Object retVal =  pjp.proceed();

    boolean hasClassAnnotation = false;
    for(Class<?> i: pjp.getTarget().getClass().getInterfaces()) {
        if(i.getAnnotation(ThrowResourceNotFound.class) != null) {
            hasClassAnnotation = true;
            break;
        }
    }

    if(hasClassAnnotation && isObjectEmpty(retVal))
        throw new RuntimeException(messageSource.getMessage("exception.resourceNotFound", new Object[]{}, LocaleContextHolder.getLocale()));

    return retVal;
}
娄飞鸾
2023-03-14

尽管OP严重依赖于AeyJ解决方案,但目前的问题并不直接表明解决方案应该仅限于AeyJ。因此,我想提供一种非AeyJ的方法来建议Spring Data JPA存储库。它基于将自定义Interceptor添加到准系统Spring AOP代理拦截器链中。

首先,配置您的自定义RepositoryFactoryBean,例如。

@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class ConfigJpaRepositories {
}

接下来,实现CustomRepositoryFactoryBean以将您自己的RepositoryProxyPostProcess添加到JpaRepositoryFactory

class CustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T , I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

  protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
    RepositoryFactorySupport factory = super.createRepositoryFactory(em);
    factory.addRepositoryProxyPostProcessor(new ResourceNotFoundProxyPostProcessor());
    return factory;
  }

}

您的存储库ProxyPostProcessor实现应该将您的方法拦截器添加到特定存储库的代理工厂(检查存储库信息):

class ResourceNotFoundProxyPostProcessor implements RepositoryProxyPostProcessor {

    @Override
    public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
        if (repositoryInformation.getRepositoryInterface().equals(CityRepository.class))
            factory.addAdvice(new ResourceNotFoundMethodInterceptor());
    }

}

在你的方法拦截器(顺便说一句,它是org.aopalliance.aop.Advice的子接口,所以仍然是一个建议:)中,你拥有AspectJ关于建议的全部功能:

class ResourceNotFoundMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        ResourceNotFound resourceNotFound = method.getAnnotation(ResourceNotFound.class);
        //...
        Object result = invocation.proceed();
        //...
        return result;
    }
}   
訾高明
2023-03-14

如果您想在存储库级别拦截存储库调用,您实际上不需要为此引入自定义注释。您应该能够使用普通类型匹配来实现这一点:

 @Pointcut("execution(public !void org.springframework.data.repository.Repository+.*(..))")

这将拦截所有扩展Spring数据存储库接口的Spring bean的所有非void方法的执行。

在Spring数据示例库中可以找到一个稍微相关的示例。

 类似资料:
  • 问题内容: 我无法为spring数据jpa存储库提供建议。目的是在特定存储库中使用自定义注释(在此示例中为ResourceNotFound)进行注释的(非常规)所有非公共方法,并在返回值为或者为空集合时引发异常。 以下建议是将用注释的接口实现的所有公共方法进行连接。 该方法的工作原理,当切入点isspecified为: 但是,未拾取注释。这可能是由于存储库接口的基础类是一个(代理的)不具有特定注释

  • 问题背景 之前做springboot项目在操作数据库方面一直在使用的是Mybatis,最近在查阅资料的时候接触到了SpringData JPA与SpringData JDBC,想问一下大佬们,这三个框架如何选型

  • 问题内容: 是否可以使用Spring Data创建只读存储库? 我有一些链接到视图的实体,还有一些子实体,我想为其提供一个存储库,其中包含的某些方法,以及带有批注的某些方法。我想避免提供像和这样的方法,因为它们没有意义,并且可能会产生错误。 谢谢! 问题答案: 是的,方法是添加手工制作的基础存储库。您通常使用以下内容: 现在,您可以使刚刚定义的具体回购扩展: 定义基本存储库的关键部分是,方法声明

  • 我对SpringData和JPA有问题。当我向HomeRepository接口添加方法时,我得到一个错误。我使用的是JPararePository接口,在pom.xml文件中有一个MySQL数据库集。这些只是我对spring的开始,所以我需要一些了解spring的人的帮助。下面是我的代码和日志: 主页库: 用户存储库: 日志:

  • 问题内容: 我需要一个用于Java的非常基本的键值存储。我从HashMap开始,但似乎HashMap的空间效率有些低下(我正在存储约2000万条记录,并且似乎需要约6GB RAM)。 映射为,因此我考虑使用GNU Trove ,并将映射值存储为ascii字节数组而不是String。 作为替代方案,是否存在仅需要添加jar文件,不立即将整个映射保存在RAM中并且仍然相当快的键值存储? 问题答案: 使

  • 如何在一个类中创建和实例化jpa存储库?我现在的情况是,我必须在一个泛型类中为不同的实体创建存储库。 我可以很容易地为Neo4j存储库这样做, 对于JpaRepostory,我检查了留档,发现了这个, 我不确定如何在上面的代码中实例化工厂。 另外,我不能像为Neo4j那样通过指定域类来创建存储库吗?