【问题标题】:what is the best way to autowire parent class field in spring?在春季自动装配父类字段的最佳方法是什么?
【发布时间】:2019-04-03 03:50:12
【问题描述】:

当我使用spring框架时,我发现一些应该被提取的东西,例如,服务组件(或自动装配的成员变量)。 代码如下:

abstract class Payment {

    PaymentService paymentService;

    void setPaymentService(OrderPaymentService paymentService) {
        this.paymentService = paymentService;
    }

}    

@Component
public class CancelPayment extends Payment{
    private OtherService2 otherSerivce2;

    @Autowired
    @Override
    public void setPaymentService(PaymentService paymentService) {
        super.setPaymentService(paymentService);
    }

    @Autowired
    public CancelPayment(OtherService2 s2) {
        this.otherSerivce2 = s2;
    }
}

@Component
public class CreatePayment extends Payment{
    private OtherService1 otherSerivce1;

    @Autowired
    @Override
    public void setPaymentService(PaymentService paymentService) {
        super.setPaymentService(paymentService);
    }

    @Autowired
    public CreatePayment (OtherService1 s1) {
        this.otherSerivce1 = s1;
    }
}

如您所见,我在每个子类中都使用了 setter 注入。这是否比自动装配其父级成员变量更好?

【问题讨论】:

  • 您在此处展示的基本思想或结构没有问题,但存在具体问题。您将三个 PaymentService 对象自动装配到同一个组件中。您如何期望 Spring 知道它应该在每个点注入哪些不同类型的 PaymentService bean?我假设您不希望将同一个 bean 注入所有三个注入点,但这就是 Spring 可以对您显示的代码所做的全部。要么你只有一个 PaymentService 对象,要么 Spring 不会喜欢这个代码。
  • ...如果您注册了多个 PaymentService bean,请相信 Spring 会抱怨它有太多 PaymentService 类型的候选 bean,因此不知道该怎么做。 - 有一些方法可以解决这个问题,比如 @Qualifier 注释。
  • 在子级和父级都定义 paymentService 变量也很奇怪,而且我不确定是否合法。我不确定您认为这对于调用超类的 setter 的 setter 方法意味着什么,但您的构造函数直接设置值。充其量,这是非常令人困惑的。
  • @Steve 对不起,在子级和父级都定义支付服务,这是一个笔误。我只会在父母中保留它
  • 如果不需要子特定的支付服务,那么在 Parent 中定义并继承它似乎 更干净

标签: java spring


【解决方案1】:

以下是 Spring 团队的 DI 指南:


Spring 推荐的一般准则(请参阅基于构造函数的 DI 或基于 Setter 的 DI 的部分)如下:

  • 对于强制依赖或当目标是不变性时,使用 构造函数注入

  • 对于可选或可变依赖,使用setter注入

  • 在大多数情况下避免字段注入


现在,如果您确定要使用 PaymentService,我建议您像这样在抽象类中使用构造函数注入,这样对象就不会在没有依赖关系的情况下实例化,也使其更加不可变、更清晰和线程安全:

abstract class Payment {
    PaymentService paymentService;


    public Payment(OrderPaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

然后你可以像这样简单地在你的扩展类上调用 super:

@Component
public class CreatePayment extends Payment{
    private OtherService1 otherSerivce1;

    @Autowired
    public CreatePayment(PaymentService paymentService) {
        super(paymentService);
    }
}

这只是允许您使用构造函数注入父类(如果 paymentService 是强制性的)。

【讨论】:

  • 这行得通吗? @Autowired 导致 Spring 创建一个 CreatePayment bean 并将 PaymentService bean 传递给 ITS 构造函数?我不知道这会起作用。 - 我知道你可以在基类中自动装配 setter 和字段,但不能在构造函数中自动装配。
  • 是的,实际上构造函数 DI 是最喜欢的,这是一个更复杂的例子,因为继承,但是是的。不建议使用字段 DI,因为它容易产生代码异味,并且您不能使其不可变(最终),从而降低线程安全性。使用 setter,您有可能不会调用它,因此可能不会为实例提供依赖项(除非您使用 @Required 对其进行注释)。所以是的,我强烈建议尽可能使用构造函数注入。
  • @Steve always 使用构造函数自动装配。它更容易测试,您可以在 ctor 中编写验证逻辑,而不是编写 PostConstruct 方法,并且 - 在我看来最大的好处 - 它提供了 bean 依赖项的非常清晰的文档。
猜你喜欢
  • 2012-08-10
  • 2013-04-26
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 2017-12-13
  • 2021-08-08
  • 1970-01-01
相关资源
最近更新 更多