@Primary 等效于自动装配的 Spring JPA 存储库
Posted
技术标签:
【中文标题】@Primary 等效于自动装配的 Spring JPA 存储库【英文标题】:@Primary equivalent for autowired Spring JPA repositories 【发布时间】:2016-02-03 11:16:45 【问题描述】:我在应用程序中使用 Spring JPA 存储库和实体。现在,在该应用程序的风格中,我需要扩展我的一个实体并提供扩展存储库。
对于我需要覆盖/扩展的所有其他 bean,我只需创建一个新实现并使用 @Primary 对其进行注释,这样它将自动装配而不是默认实现。
但是,对于存储库,这不起作用。我可以使用 @Primary 注释新存储库,但它没有任何效果(两个 bean 都已找到,因此无法自动装配)。这是有道理的,因为存储库是一个接口而不是一个实现,实现是由 Spring 动态提供的。
我能否以某种方式告诉 Spring(通过存储库上的注释或通过配置)使用哪个存储库?还是我必须像 Using @Primary in Spring Data JPA repositories 那样手动解决问题,或者我应该想出一种存储库提供程序而不是自动装配?
编辑让事情更清楚:
假设我有一个实体A
@Entity
public class A
@Id
private long id;
及其存储库
public ARepository extends Repository<A, Long>
现在我将它扩展到实体B
@Entity
public class B extends A
public interface BRepository extends ARepository
通常,根据文档,您使用这样的存储库:
@Autowired
private ARepository repository;
但是,这确实不起作用,因为现在有两个 ARepository
类型的 bean。对于我自己实现的 bean,我会在扩展类上使用 @Primary
,但对于存储库,在编译时没有实现接口。
【问题讨论】:
为什么为该实体扩展实体和存储库需要您在第二段中描述的内容。 ...也许应该改写第 2 段 - 我(并且没有其他人接缝)了解您想要做什么/您的问题是什么。 @Ralph 我添加了一些示例代码来解释我的问题。还有一个链接问题,我尝试使用存储库工厂而不是正常的自动装配。 现在我明白了。 - 有趣的问题。 【参考方案1】:我能以某种方式告诉 Spring(通过存储库上的注释或通过 配置)使用哪个存储库?
是的,你可以。首先,您为每个存储库类指定一个唯一的 bean 名称。
@Repository("myARepository")
public ARepository extends Repository<A, Long>
@Repository("myBRepository")
public interface BRepository extends ARepository
然后,当您使用 ARepository
作为类型进行自动装配时,您应该使用 @Qualifier
注释来告诉 Spring 您想要哪个存储库。
@Autowire
@Qualifier("myBRepository")
private ARepository repository;
这将自动连接BRepository
【讨论】:
【参考方案2】:仅作记录,可以按照此处Using @Primary in Spring Data JPA repositories 的建议将@Primary
支持添加到JPA 存储库中
我对缺失代码的实现:
private boolean isSpringDataJpaRepository(Class<?> beanClass)
return JpaRepositoryFactoryBean.class.isAssignableFrom(beanClass);
我认为@Ralph 的答案更好,因为类型安全。
【讨论】:
【参考方案3】:我会从这个答案中调整这个想法:https://***.com/a/27549198/280244 和这个 git 示例 https://github.com/netgloo/spring-boot-samples/tree/master/spring-boot-springdatajpa-inheritance/src/main/java/netgloo/models
引入一个标记为@NoRepositoryBean
的通用抽象Repository
@NoRepositoryBean
public interface AbstractARepository<T extends A>
extends Repository<T, Long>
T findByName(String name); //or what ever your queries are
public ARepository extends AbstractARepository<A>
//almost emtpy
public BRepository extends AbstractARepository<B>
//queries that are special for B
现在你可以注入ARepository
和BRepository
,而且都是类型保存!
【讨论】:
当然我读过你之前链接的问题,但我认为它不适用于我的情况。不过,您的代码示例非常有趣。如果您想将A
与B
一起使用,这是一个很好的解决方案。但是,就我而言,我想以@Autowire ARepository
实际上返回BRepository
的实现的方式“覆盖”实体,以便将实体创建为B
,并且如果我想不必再次加载使用B
的功能。这将是传统 @Primary
bean 的行为。
@zero_cool:仔细看看我的建议。关键是,ARepository
和 BRepository
是空的。您可以按类型注入ARepository
或BRepository
。当然BRepository
不会扩展ARepository
,但我不认为这是必要的。
@zero_cool:但是我你永远不会再加载B
实体,那么根本没有理由拥有BRepository
。 - 或者你为什么需要它?
也许我的用例并不常见。如原始问题所述(可能不清楚),我得到了一个仅提供A
和ARepository
的应用程序(以及您的建议AbstractARepository
)。现在在应用程序的味道中,例如针对特定客户的定制,我需要将A
扩展到B
(以及相应的存储库),以便A
在应用程序中完全被B
替换。在原始应用程序中,我按类型自动装配ARepository
,现在必须返回BRepository
的实现实例,从而创建B
的实例而不是A
我意识到这确实是解决方案,只是缺少一个链接。存储库以这种方式工作正常。但是,如果我不希望 A
类型的实体出现在我的数据库中,我就不能在我的主应用程序中使用 repository.save(new A());
创建它们。这将使存储库通过dtype
列区分类型。我需要有一种工厂,以我的口味返回B
的实例。我一直认为存储库有问题,但实际上我也需要替换实体实例。感谢拉尔夫的耐心:)以上是关于@Primary 等效于自动装配的 Spring JPA 存储库的主要内容,如果未能解决你的问题,请参考以下文章
Spring注解驱动开发第20讲——使用@Autowired@Qualifier@Primary这三大注解自动装配组件,你会了吗?