Spring @Autowire 注解用于属性或构造函数的区别

  • 背景
  • 回复1
  • 回复2
  • 回复3

背景

因此,由于我一直在使用 Spring,所以如果我要编写具有依赖项的 Service,我将这样实现:
方法 A

@Component
public class SomeService {
     @Autowired 
     private SomeOtherService someOtherService;
}

但是我现在发现了使用另一种约定也可以实现相同目标的代码:
方法 B

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}

这两种方法都可以达到相同的目的。但是使用第二种方式有一些优势吗?对我来说,它在类和单元测试中创建了更多代码。 (必须编写构造函数,而不能使用 @InjectMocks

有什么我不清楚的吗? 除了将代码添加到单元测试中之外,Autowired 构造函数还有其他功能吗? 方法 B 是进行依赖注入更优的吗?

回复1

是的,实际上建议使用方法 B(称为构造函数注入),而不是使用属性注入,它具有以下优点:

  • 依存关系明确。在测试或在任何其他情况下实例化对象时(例如在 config 类中显式创建 bean 实例),都不会忽略此构造方法;
  • 依赖关系可以是 final,这有助于增强鲁棒性和线程安全性;
  • 您不需要反射来设置依赖项。InjectMocks 仍然可用,但不是必需的。 您可以自己创建 mocks 并通过调用构造函数将其注入。


回复2

我将用简单的话向您解释:

  • 方法 A中,您允许任何类(在Spring容器外部/内部的不同类中)使用默认构造函数(例如 new SomeService())创建实例,这是不规范的。因为您需要 SomeOtherService 对象(作为依赖项) 为您的 SomeService
  • 方法 B是首选方法,因为它允许在没有实际解决 SomeOtherService 依赖关系的情况下创建 SomeService 对象。

回复3

请注意,从Spring 4.3开始,您甚至不需要在构造函数上使用 @Autowired,因此您可以使用 Java 样式编写代码,而不必使用 Spring 的注释。您的代码段如下所示:

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

    public SomeService(SomeOtherService someOtherService){
        this.someOtherService = someOtherService;
    }
}