【问题标题】:Why do I need a fragment interface for repositories that stand on their own?为什么我需要一个独立的存储库的片段接口?
【发布时间】:2021-03-09 03:24:27
【问题描述】:

引用https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

要使用自定义功能丰富存储库,您必须首先定义片段接口和自定义功能的实现

示例 32 表明,即使是不扩展 CrudRepository(如示例 31)或合并多个存储库接口(如示例 33)的存储库也是如此。

它还指出

与片段接口对应的类名中最重要的部分是Impl后缀

但不解释原因。

自定义存储库/存储库片段如何工作,为什么普通 bean 上的 @Repository 注释不够?

【问题讨论】:

  • 如果您不想扩展存储库,则不需要片段,只需创建一个实现并注入该接口即可。如果您想将功能添加到需要自定义实现的存储库中,那么您需要一个片段并遵守此标准(因此您的实体只有 1 个存储库而不是 2 个)。

标签: java spring spring-data-jpa spring-data repository


【解决方案1】:

您基本上有两种选择。第一个是提供每个存储库接口的实现。这可以在您的示例中看到。在这种情况下,您可以为一个实体存储库覆盖存储库的默认实现。这对于增强特殊实体存储库很有用,例如用于报告等。

另一个选项是当您想为所有存储库提供基本实现时,您需要使用基本存储库片段。当您只想为每个自定义存储库提供一个基本实现时,存储库片段可能非常有用。让我给你举个例子:

CustomReadRepository:

@NoRepositoryBean
public interface CustomReadRepository<T> extends Repository<T, String> {

  public List<T> someMethod();

  public List<T> someHighPerformanceMethod();
}

现在假设我们想要一个结合不同存储库的接口并将其命名为DataRepository

数据存储库:

@NoRepositoryBean
public interface DataRepository<T>
  extends CrudRepository<T, String>, CustomReadRepository<T> {
}

以下接口现在是扩展整个存储库的实体的特定存储库

@Repository
public interface UserRepository extends DataRepository<UserEntity> {

}

@Repository
public interface OrderRepository extends DataRepository<OrderEntity> {

}

现在我们只想为所有特定的存储库(OrderRepository、UserRepository 等)提供一个实现。

public class CustomReadRepositoryImpl<T> implements CustomReadRepository<T> {

  private static final EntityPathResolver resolver = SimpleEntityPathResolver.INSTANCE;

  private final JpaEntityInformation<T, ?> entityInformation;
  private final EntityManager entityManager;
  private final Querydsl entityManager;

  public CustomReadRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
      EntityManager entityManager) {
    this.entityManager = entityManager;
    this.entityInformation = entityInformation;
  }

  @Override
  public List<T> someMethod() {
    //do something and return result
  }
 
  @Override
  public List<T> someHighPerformanceMethod() {
    // do some high performance querying here
  }
}

因此,您基本上可以在这里做的是增强您的存储库并仅提供一种有用的实现,例如覆盖 Spring 的默认实现(以使其更快或任何原因)。您还可以提供新的自定义存储库和实现。

要使您的片段实现在 Spring 中可访问,您必须执行以下操作:

CustomRepositoryFactoryBean:

public class CustomRepositoryFactoryBean<T extends Repository<S, I>, S, I>
    extends JpaRepositoryFactoryBean<T, S, I> {

  public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
    super(repositoryInterface);
  }

  protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
    return new CustomRepositoryFactory(entityManager);
  }

这个 bean 应该在 Main 类中使用:

主类:

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

以及工厂的实现:

CustomRepositoryFactory:

public class CustomRepositoryFactory extends JpaRepositoryFactory {

  private final EntityManager entityManager;

  public CustomRepositoryFactory(EntityManager entityManager) {
    super(entityManager);
    this.entityManager = entityManager;
  }

  @Override
  protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
    RepositoryFragments fragments = super.getRepositoryFragments(metadata);

    if (CustomReadRepository.class.isAssignableFrom(
        metadata.getRepositoryInterface())) {

      JpaEntityInformation<?, Serializable> entityInformation = 
          getEntityInformation(metadata.getDomainType());

      Object customRepoFragment = getTargetRepositoryViaReflection(
          CustomReadRepositoryImpl.class, entityInformation, entityManager);

      fragments = fragments.append(RepositoryFragment.implemented(customRepoFragment));
    }

    return fragments;
  }

如果你想看一种真实的例子,请看问题here

【讨论】:

    猜你喜欢
    • 2012-05-23
    • 2016-10-25
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多