在IDEA中使用@Autowired注解,会提示如下内容,那么为什么会出现以下提示呢?下面我们进一步分析分析
原因分析
关于这个问题,答案其实比较统一,通俗易懂其实也很容易理解。
- 初始化问题
Java初始化类的顺序:父类静态字段>父类静态代码块>子类静态字段>子类静态代码块>父类成员变量>父类结构代码块>父类构造函数> 子类成员变量 > 子类构造代码块 > 子类构造函数。
自动装配注入必须在子类构造函数之后排队。 SpringIOC不会判断依赖bean是否为null,JVM编译时不会有问题,但如果使用不当,运行起来可能会出现空指针异常。
- 容易过度依赖IOC
@Autowired 由 Spring 提供,而 @Resource 由 JSR-250 提供,这是一个 Java 标准。前者会警告,后者不会,因为前者导致应用程序和框架之间存在强绑定。如果换成别的IOC框架,就无法注入成功。其实对于这方面,我觉得大部分情况下不会有什么问题。
- 其他
我在网上看到了一些其他方面的总结,比如:依赖太多但不够明显,违反了单一职责原则; immutable objects不能像constructors之类的注入,这类问题需要结合个人实际开发判断。
对于@Autowired的使用,虽然强绑定了业务代码和框架,但是字段注入确实大大简化了代码。追求完全松耦合其实过于理想化,在实际使用中应该追求一个平衡,否则过度追求松耦合得不偿失。
替换方案
除了使用@Autowired,也可以使用@Resource 替换@Autiwired 方法就是其中之一。只需要修改一个注解,可以看到,修改后,警告信息就没有了
下面再介绍几种其它方式
set方法
@RestController
public class TestAutoController {
ITestAutoService testAutoService;
/*
* 基于set注入
* */
@Autowired
public void setTestAutoService(ITestAutoService testAutoService) {
this.testAutoService = iTestAutoService;
}
@GetMapping("/getTestAtuo")
public Result<TestAutoDto> getAuto() {
return testAutoService.getAuto();
}
}
该方法也使用了@Autowired注解,但作用于成员变量的Setter函数,而不是像Fied注入那样作用于成员变量。
构造器
@RestController
public class TestStructController {
ITestStructService testStructService;
/*
* 基于构造方法注入
* */
public TestStructController(ITestStructService testStructService) {
this.testStructService = iTestStructService;
}
@GetMapping("/getTestStruct")
public Result<TestStructDto> getStruct() {
return testStructService.getStruct();
}
}
它的优点是使用构造函数注入,这需要对象创建的顺序,它将避免循环依赖问题,是比较可靠的方法。
构造器的简化版(lombok)
引入maven依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
然后,我们可以在创建时使用@RequiredArgsConstructor注释,这将帮助我们创建一个构造函数,final关键字是必不可少的。
@RestController
@RequiredArgsConstructor
public class TestArgsController {
/*
* 用@RequiredArgsConstructor注解,也可以应用于service层
* */
private final ITestArgsService testArgsService;
@GetMapping("/getArgs")
public Result<?> getArgs() {
return testArgsService.getArgs();
}
}
总结
在使用中,使用构造的方法是比较可行的,而有了lombok,实际上可以非常轻松地实现。
发表评论