还在用@Autowired注入?试试这个最佳实践
前言
Spring框架本身有各种不同的方式来执行依赖项的注入。灵活的选择是Spring框架的强项。然而,并非所有依赖注入方式都被认为是最佳实践。
依赖注入
接下来我们通过一些代码示例,来分别实现Spring的多种依赖注入的方式。首先我们有一个MyService
,这个service
中有一个sayHi()
的服务,我们在Controller
中尝试用不同的方式进行注入。
@Service
public class MyService{
public String sayHi(){
return "hello Spring.";
}
}
属性注入
@Controller
public class FieldController {
@Autowired
private MyService service;
public String saySomething(){
return service.sayHi();
}
}
通过属性注入的方式,Spring会在转配Bean时通过反射注入。这种方式虽然可以满足依赖的注入,但是在测试时,要么需要启动Spring Context,要么使用一些Spring实用程序执行依赖项注入以进行测试。
我们可以通过为私有属性提供setter来改进这一点。getter和setter通常被认为是面向对象编程中的最佳实践。通过注解setter方法来指导Spring使用setter进行依赖项注入是很简单的。
方法注入
@Controller
public class FieldController {
private MyService service;
@Autowired
public void setService(MyService service){
this.service = service;
}
public String saySomething(){
return service.sayHi();
}
}
这是对使用私有属性注入的一种改进方式,但是还是会有人认为代码太多。
构造器注入
当使用构造函数注入属性时,必须要提供@Autowired
注解。这是一个很好的功能,它为我们减少了一些代码。从Spring Framework 4.2
版本开始,用于依赖注入的构造函数注解已经是可选的。
@Controller
public class FieldController {
private MyService service;
public FieldController(MyService service){
this.service = service;
}
public String saySomething(){
return service.sayHi();
}
}
基于构造器的依赖注入通常被认为是最佳实践。有一段时间,我个人喜欢基于setter的注入,但后来我转而支持基于构造器的注入。
基于构造器的注入方式目前主要还有两个问题。
- 我们服务的类型是具体类型。硬类型的依赖项注入并不被认为是最佳实践。
- 我们要注入的属性没有声明为final,因此,从理论上讲,可以在实例化后修改注入的属性。
依赖注入最佳实践
依赖项注入的最佳实践是利用接口、构造函数和final属性。
最佳实践服务接口
public interface BpService {
String getHello();
}
最佳实践服务实现
@Service
public class BpServiceImpl implements BpService{
@Override
public String getHello(){
return "The Best Hello!";
}
}
使用Lombok
接下来,使用Lombok项目在依赖注入方面的原因是:
- 声明接口类型的final属性
- 使用Lombok所需的args构造函数注解
Lombok Controller
@Controller
@AllArgsConstructor
public class BpController {
private final BpService bpService;
public String saySomething(){
return bpService.getHello();
}
}
这是一个很好的方式,代码会保持的非常干净。在使用Spring时,经常需要几个自动注入的属性。当需要添加一个bean时,只需声明为final的属性就可以。不需要再添加 @Autowired
注解,也不需要添加setter
方法或者构造器。
我在日常编码中使用这种方式已经有一段时间了。这绝对是一件省时的事,并且代码也会变得清晰。
小结
本期我给大家分享了Spring依赖注入的不同方式,主要有:
- 通过私有属性Autowired注入;
- 通过setter方法注入;
- 通过构造器注入;
但是这三种方式都不是最佳实践,我推荐的最佳实践是使用Lombok的@AllArgsConstructor
注解,并将需要注入的bean定义为final属性。