【问题标题】:Spring JPA: How to get dependencies right with injection?Spring JPA:如何通过注入获得正确的依赖关系?
【发布时间】:2015-03-12 08:08:03
【问题描述】:

我的数据模型由三个对象组成,我们称它们为ABCABBC 具有一对多关系。它们仅被建模为接口。

为了获得它们的具体版本,我有接口AProviderBProviderCProvider,它们提供创建、检索和删除操作。

我现在正在通过spring-boot-starter-data-jpa 使用 Spring-JPA 和 Hibernate 进行实现。为此,我有三个@Entitys InternalAInternalBInternalC,它们没有实现ABC 接口,但仅用作传输对象。为了访问它们,我使用 Spring 中自动生成的存储库(请参阅 CrudRepository)。

为了创建“真实”对象,我实现了XProvider 接口,这些接口注入了它们必要的依赖项。这个结构如下(我更喜欢javax.inject风格注入):

@Component
public class AProviderImpl implements AProvider {

    @Inject
    private InternalARepository _aRepository;

    // implementation
}

@Component
public class BProviderImpl implements BProvider {

    @Inject
    private InternalBRepository _bRepository;

    @Inject
    private AProvider _aProvider;

    // implementation
}

@Component
public class CProviderImpl implements CProvider {

    @Inject
    private InternalCRepository _cRepository;

    @Inject
    private BProvider _bProvider;

    // implementation
}

我发现这应该可以工作,AutowireCapableBeanFactory 正确地确定了首先要实例化什么。但这仅适用于 BProviderImpl,例如,在删除 CProviderImpl 时。只要CProviderImpl 存在,初始化就会失败并显示No qualifying bean of type [com.somewhere.BProvider] found

如果我使用@Autowired 代替@Inject 没有区别。

我使用调试器逐步完成了初始化过程,并且确实首先初始化了 CProvider,即 bean 工厂没有正确地确定它需要 BProvider,而后者又首先需要 AProvider

我目前的解决方法是像这样使用@DependsOn

@Component("myAProvider")
public class AProviderImpl implements AProvider { ... }

@Component("myBProvider")
@DependsOn("myAProvider")
public class BProviderImpl implements BProvider { ... }

@Component("myCProvider")
@DependsOn("myBProvider")
public class CProviderImpl implements CProvider { ... }

这可行,但我在其他地方读到这是代码异味,应该避免,因为它引入了隐式依赖关系。目前,这对一个模块来说都是本地的,所以在那里没有问题,但后来我的模型会增长,我的模型元素和提供者会分布在多个模块中,所以在王国到来之前我不能使用@DependsOn

有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: java spring spring-boot dependency-injection


    【解决方案1】:

    您可以使用@Order 注释,这将启用优先加载Bean,并且不会像@DependsOn 那样污染您的加载层次结构。有了这个,您当然可以在以后毫无问题地模块化您的设计。最低订单价值具有最高优先级。

    @Component("myAProvider")
    @Order(1)
    public class AProviderImpl implements AProvider { ... }
    
    @Component("myBProvider")
    @Order(2)
    public class BProviderImpl implements BProvider { ... }
    
    @Component("myCProvider")
    @Order(3)
    public class CProviderImpl implements CProvider { ... }
    

    【讨论】:

    • 我刚刚尝试过,但没有成功。我得到“没有合格的bean”例外。我发现使用@Lazy 似乎可以解决问题。这样,bean 会按照 bean 工厂认为它必须使用的顺序进行初始化,但所有注入的东西都会在第一次需要时进行初始化。
    【解决方案2】:

    我找到了另一种解决方法:延迟初始化。由于我的XProviders 的初始化不是长时间运行的,我只是添加了@Lazy 注释。这样,Spring 会创建未初始化的实例并将它们添加到注册表中,当稍后访问注入的依赖项时,它会被初始化。

    我不知道这是否是最好的解决方案,但我认为它比使用 @DependsOn 更好,它应该可以跨越模块边界。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-22
      • 1970-01-01
      • 2020-06-18
      • 2012-05-27
      • 2019-09-29
      相关资源
      最近更新 更多