因此,由于我一直在使用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)

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


当前回答

很少有@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中调用被通知的方法可能需要这样做。这里和这里也讨论了自注入。

其他回答

事实上,根据我的经验,第二种选择更好。不需要@Autowired。事实上,更明智的做法是创建与框架耦合不太紧密的代码(就像Spring一样)。您希望代码尽可能采用延迟决策方法。这是尽可能多的pojo,以至于框架可以很容易地交换出来。 所以我建议你创建一个单独的Config文件,并在那里定义你的bean,如下所示:

在somesservice .java文件中:

public class SomeService {
    private final SomeOtherService someOtherService;

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

在ServiceConfig.java文件中:

@Config
public class ServiceConfig {
    @Bean
    public SomeService someService(SomeOtherService someOtherService){
        return new SomeService(someOtherService);
    }
}

事实上,如果你想深入了解它的技术,使用字段注入(@Autowired)会产生线程安全问题(以及其他问题),这显然取决于项目的大小。检查这来了解更多的优点和缺点的自动装配。实际上,关键的人建议你使用构造函数注入而不是字段注入

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

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

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

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

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

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注释。然后你可以使用这样的语句:

@RestController
public class NiceController {

    private final DataRepository repository;

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

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