因此,由于我一直在使用Spring,如果我要编写一个有依赖关系的服务,我会这样做:

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

我现在遇到了使用另一种约定来实现相同目标的代码

@Component
public class SomeService {
    private final SomeOtherService someOtherService;

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

我知道这两种方法都有效。但是选择B有什么好处吗?对我来说,它在类和单元测试中创建了更多的代码。(必须写构造函数,不能使用@InjectMocks)

我遗漏了什么吗?除了将代码添加到单元测试之外,自动连接构造函数还有其他功能吗?这是一种更可取的依赖注入方式吗?


当前回答

我更喜欢构造注入,只是因为我可以将我的依赖标记为final,这在使用属性注入属性时是不可能的。

你的依赖关系应该是最终的,即不被程序修改。

其他回答

很高兴知道

如果只有一个构造函数调用,则不需要包含@Autowired注释。然后你可以使用这样的语句:

@RestController
public class NiceController {

    private final DataRepository repository;

    public NiceController(ChapterRepository repository) {
        this.repository = repository;
    }
}

... Spring数据存储库注入的例子。

Autowired构造函数提供了一个钩子,可以在将自定义代码注册到spring容器之前添加它。假设SomeService类扩展了另一个名为SuperSomeService的类,并且它有一个以名称作为参数的构造函数。在这种情况下,Autowired构造函数工作得很好。同样,如果有其他成员要初始化,可以在将实例返回给spring容器之前在构造函数中进行初始化。

public class SuperSomeService {
     private String name;
     public SuperSomeService(String name) {
         this.name = name;
     }
}

@Component
public class SomeService extends SuperSomeService {
    private final SomeOtherService someOtherService;
    private Map<String, String> props = null;

    @Autowired
    public SomeService(SomeOtherService someOtherService){
        SuperSomeService("SomeService")
        this.someOtherService = someOtherService;
        props = loadMap();
    }
}

很少有@Autowired更可取的情况。 其中之一是循环依赖。想象一下下面的场景:

@Service
public class EmployeeService {
    private final DepartmentService departmentService;

    public EmployeeService(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
}

and

@Service
public class DepartmentService {
    private final EmployeeService employeeService;

    public DepartmentService(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }
}

Then Spring Bean Factory will throw circular dependency exception. This won't happen if you use @Autowired annotation in both beans. And this is understandable: the constructor injection happens at very early stage of Spring Bean initialization, in createBeanInstance method of Bean Factory, while @Autowired-based injection happens way later, on post processing stage and is done by AutowiredAnnotationBeanPostProcessor. Circular dependency is quite common in complex Spring Context application, and it needs not to be just two beans referring one another, it could a complex chain of several beans.

另一个@Autowired非常有用的用例是自我注入。

@Service
public class EmployeeService {
    
    @Autowired
    private EmployeeService self;

}

从同一个bean中调用被通知的方法可能需要这样做。这里和这里也讨论了自注入。

我希望我不会因为表达我的观点而被降级,但对我来说,选项A更好地反映了Spring依赖注入的强大功能,而在选项B中,您将类与依赖项耦合在一起,实际上,如果不从构造函数传递依赖项,就无法实例化对象。依赖注入通过实现控制反转来避免这种情况,所以对我来说选项B没有任何意义。

有一种方法可以使用Lombok中的@ requeiredargsconstructor注释通过构造函数注入依赖项

@RequiredArgsConstructor
@Service
 class A {
     private final B b // needs to be declared final to be injected
}

这样就不需要指定构造函数