8

前言

在我们使用Spring进行开发的时候,经常需要进行依赖注入,而@Autowired注解是一个常用的依赖注入方式,但是我们会发现当你使用@Autowired进行注入的时候,idea会出现一个黄色的下划线

image.png

idea会提醒field injection is not recommented 不推荐这种注入方式,而是更推荐构造器的方式进行注入,翻了下官网,Spring团队通常支持构造函数注入,确保当前注入的不能是null

image.png

构造器注入的优势

从官网的介绍上看,使用构造器主要是因为它有几个明显的好处

确保依赖不为 null

构造器注入要求在创建对象时就传入所有依赖,这样可以保证这些依赖不会为 null。而字段注入是在对象创建后才进行,可能会导致某些依赖没有正确注入,出现意料之外的错误。

如果使用@Autowired是可以接受一个不存在的Bean,你只要把required设置为false

@RestController
@RequestMapping("apiRequest")
public class ApiRequestController {
    @Autowired(required = false)
    private ApiRequestService apiRequestService;
}

image.png

public class ApiRequestServiceImpl implements ApiRequestService {
}

而如果使用构造器的方式的话,就必须保证这个bean必须存在

image.png

保持依赖的不可变性

构造器注入使依赖在对象创建后无法修改,从而保证对象的状态是稳定的。字段注入或Setter方法可以在对象的生命周期内修改依赖,增加了代码的不确定性和潜在的错误。

使用@Autowired字段注入的类状态可能随时发生变化,因为字段是可变的(虽然是private但非final):

image.png

可能出现的情况

    @Autowired
    private ApiRequestService apiRequestService;
    
    public void test() {
        this.apiRequestService = new ApiRequestServiceImpl();
    }

与此相对,通过构造器注入,依赖可以设置为final,一旦对象创建后,依赖就不会再被更改:

image.png

循环依赖

当两个或多个类相互依赖时,就会出现循环依赖。由于存在这些依赖关系,因此无法构造对象,执行过程中可能会出现运行时错误或死循环。

使用字段注入可能会导致循环依赖关系被忽视:

@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}


@Component
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

image.png

我们知道依赖是在需要时注入,而不是在启动的时候进行注入,因此Spring不会抛出循环依赖错误

如果使用构造器的方式


@Component
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

@Component
public class ServiceB {
    private final ServiceA serviceA;
    
    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

通过构造函数注入的话,可以在程序编译的时候出现提醒

The dependencies of some of the beans in the application context form a cycle:
应用程序上下文中的某些bean的依赖关系形成了一个循环

image.png

image.png

如何解决循环依赖问题,在其中一个加上@Lazy注解

@Component
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

image.png

总结

本文介绍了为什么不推荐使用@Autowired的原因,虽然@Autowired使用起来比较方便,但是存在为Null、不可变和循环依赖问题,使用构造器注入就能完美解决这个


kexb
474 声望15 粉丝