满心记 我在人间混日子

在IDEA中使用@Autowired注解的警告

在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,实际上可以非常轻松地实现。

发表评论

提交评论