如何从自定义实现中引用“正常”弹簧数据存储库?

Posted

技术标签:

【中文标题】如何从自定义实现中引用“正常”弹簧数据存储库?【英文标题】:How to reference the 'normal' spring data repo from a custom implementation? 【发布时间】:2015-04-06 07:55:10 【问题描述】:

我想用自定义实现扩展JpaRepository,所以我添加了一个MyRepositoryCustom 接口和一个扩展此接口的MyRepositoryImpl 类。

有没有办法在我的自定义类中从JpaRepository 调用方法?

注意:这也是对 https://***.com/a/11881203/40064 的评论,但我认为这很常见,值得单独提问。

【问题讨论】:

我们通常建议不要扩展 JpaRepository,因为它会暴露客户通常不应该知道的商店特定 API。 我同意,我尽可能使用CrudRepository,但这是一个迁移项目,所以有时我需要来自JpaRepository的一些东西 【参考方案1】:

tl;博士

要将核心存储库接口注入自定义实现,请将Provider<RepositoryInterface> 注入自定义实现。

详情

实现该工作的核心挑战是正确设置依赖注入,因为您将要在要扩展的对象和扩展之间创建循环依赖。但是,这可以通过以下方式解决:

interface MyRepository extends Repository<DomainType, Long>, MyRepositoryCustom 
  // Query methods go here


interface MyRepositoryCustom 
  // Custom implementation method declarations go here


class MyRepositoryImpl implements MyRepositoryCustom 

  private final Provider<MyRepository> repository;

  @Autowired
  public MyRepositoryImpl(Provider<MyRepository> repository) 
    this.repository = repository;
  

  // Implement custom methods here

这里最重要的部分是使用Provider&lt;MyRepository&gt;,这将导致Spring 为该依赖项创建一个延迟初始化的代理即使它首先为MyRepository 创建一个实例。在自定义方法的实现中,您可以使用 ….get()-method 访问实际的 bean。

Provider 是来自@Inject JSR 的接口,因此是标准化接口,需要对该 API JAR 的额外依赖。如果您只想坚持使用 Spring,您可以使用 ObjectFactory 作为替代接口,但会获得完全相同的行为。

【讨论】:

我猜 MyCustomRepository 应该是 MyRepositoryCustomRepository 也接受 2 个参数。我很清楚你知道这一点,但它会让其他偶然发现它的人的答案更完整:) 我已经按照您的预期修复了类型签名。 Manish 的回答没有退路,这是一个完全不同的目的。他的答案针对所有存储库(您表示您不想要,让我首先添加我的答案)。另外,在我的用例中,您可以访问整个存储库,而不仅仅是 SimpleJpaRepository 是否可以通过允许将MyRepositoryImpl 抽象化来支持这一点?我不知道 Spring Data 是否可以采用该抽象类并将 CrudRepo 的实现“添加”到它?它将避免使用Provider 的解决方法 谢谢奥利弗。这应该是官方文档的一部分,我从几个月开始就一直在寻找这个。 Provider在什么包里?每个库都有自己的 Provider 类。是这个 javax.inject.Provider 吗?【参考方案2】:

文档中标题为Adding custom behaviour to all repositories 的部分应该会对您有所帮助。

例如(仅用于说明目的):

public interface ExtendedJpaRepository<T, ID extends Serializable>
       extends JpaRepository<T, ID> 
    T findFirst();
    T findLast();


public class ExtendedJpaRepositoryImpl<T, ID extends Serializable>
       extends SimpleJpaRepository<T, ID>
       implements ExtendedJpaRepository<T, ID> 
  public ExtendedJpaRepositoryImpl(Class<T> domainClass, EntityManager em) 
    super(domainClass, entityManager);
  

  public T findFirst() 
    List<T> all = findAll();

    return !all.isEmpty() ? all.get(0) : null;
  

  public T findLast() 
    List<T> all = findAll();

    return !all.isEmpty() ? all.get(all.size() - 1) : null;
  

然后,配置 ExtendedJpaRepositoryImpl 以按照上面链接的文档中给出的说明使用。

由于ExtendedJpaRepositoryImpl 扩展了SimpleJpaRepository(这是JpaRepository 的实现),所以JpaRepository 中的所有方法都可以从ExtendedJpaRepositoryImpl 中调用。

【讨论】:

我不想将此添加到我的所有存储库中。这只适用于一个存储库吗? 是的,请参考我链接到的上面的部分。

以上是关于如何从自定义实现中引用“正常”弹簧数据存储库?的主要内容,如果未能解决你的问题,请参考以下文章

在使用弹簧数据存储库之前更改当前模式 - 多租户

如何从自定义反应挂钩访问数据

从自定义控件引用子项

Laravel:如何从自定义 UserProvider 返回更多数据?

如何从自定义类添加对我的 Web 服务代理的引用

如何从自定义表格视图单元类中获取对表格视图控制器的引用