GSU*_*bit 111 spring constructor dependency-injection autowired
因为我一直在使用Spring,如果我要编写一个具有依赖项的服务,我会执行以下操作:
@Component
public class SomeService {
@Autowired private SomeOtherService someOtherService;
}
Run Code Online (Sandbox Code Playgroud)
我现在遇到了使用另一个约定来实现相同目标的代码
@Component
public class SomeService {
private final SomeOtherService someOtherService;
@Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Run Code Online (Sandbox Code Playgroud)
我理解这两种方法都有效.但是使用选项B有一些优势吗?对我来说,它在类和单元测试中创建了更多代码.(必须编写构造函数而不能使用@InjectMocks)
有什么我想念的吗?除了在单元测试中添加代码之外,还有其他任何自动装配的构造函数吗?这是一种更优先的依赖注入方式吗?
JB *_*zet 153
是的,实际上建议使用选项B(称为构造函数注入)而不是现场注入,并且具有以下几个优点:
有关 更详细的文章,请参阅此博客文章,其中一位是Spring贡献者,Olivier Gierke.
dev*_*per 32
我会用简单的话来解释你:
在选项(A)中,您允许任何人(在Spring容器外部/内部的不同类中)使用默认构造函数(如new SomeService()
)创建实例,这不是很好,因为您需要SomeOtherService
对象(作为依赖项)SomeService
.
除了在单元测试中添加代码之外,还有其他任何自动装配的构造函数吗?这是一种更优先的依赖注入方式吗?
选项(B)是首选方法,因为它不允许在SomeService
不实际解析SomeOtherService
依赖关系的情况下创建对象.
sti*_*ger 24
请注意,从Spring 4.3 开始,您的构造函数甚至不需要 @Autowired,因此您可以用 Java 风格编写代码,而不是绑定到 Spring 的注释。您的代码段如下所示:
@Component
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*ník 11
很高兴知道
如果只有一个构造函数调用,则不需要包含@Autowired 注解。然后你可以使用这样的东西:
@RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
Run Code Online (Sandbox Code Playgroud)
... Spring Data Repository 注入示例。
我希望我不会因为表达我的观点而被降级,但对我来说选项 A 更好地反映了 Spring 依赖注入的力量,而在选项 B 中,您将您的类与您的依赖项耦合,实际上您无法实例化对象而不通过它的依赖来自构造函数。依赖注入的发明是为了通过实现控制反转来避免这种情况,所以对我来说选项 B 没有任何意义。
实际上,根据我的经验,第二种选择更好。无需@Autowired
. 事实上,创建与框架耦合不太紧密的代码 (和 Spring 一样好)是更明智的做法。您需要尽可能多地尝试采用延迟决策方法的代码。那是尽可能多的pojo,如此之多,以至于框架可以轻松更换。所以我建议你创建一个单独的配置文件并在那里定义你的 bean,如下所示:
在SomeService.java文件中:
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Run Code Online (Sandbox Code Playgroud)
在ServiceConfig.java文件中:
@Config
public class ServiceConfig {
@Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
Run Code Online (Sandbox Code Playgroud)
事实上,如果你想深入了解它,使用Field Injection ( @Autowired
)会出现线程安全问题(除其他外),这显然取决于项目的大小。查看此内容以了解有关Autowiring的优点和缺点的更多信息。实际上,关键人实际上建议您使用构造函数注入而不是字段注入
Autowired
constructors 提供了一个钩子,用于在将自定义代码注册到 spring 容器中之前添加自定义代码。假设SomeService
类扩展了另一个名为 name 的类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();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
44197 次 |
最近记录: |