什么是依赖注入:依赖注入就是将实例变量传入到一个对象中去,Spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。依赖注入的另一种说法是”控制反转”。通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员。而控制反转是指new实例工作不由我们程序员来做而是交给Spring容器来做。
为什么需要用到依赖注入:spring能有效组织各层对象。不论是控制层的controller对象,还是业务层的service对象,还是数据传输层的mapper对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,controller对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。
而这一切都得宜于Spring的核心机制,依赖注入。依赖注入让bean(即spring容器所管理的对象)与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。
IOC和DI:
ioc即控制反转
【将对象的创建、管理的权力(控制能力)交给框架,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转】;
di即依赖注入
【为依赖项注入值,创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖入】。
这俩概念说的是一回事。ioc是一种思想,di是具体实现方式。
循环依赖:指类与类之间互相依赖的情况,比如有类A和类B,类A中依赖类B,类B中依赖类A,由此导致项目启动的时候,不能正常加载类的情况。
Spring提供了三种依赖注入的方法,分别是:变量(接口)注入、构造器注入、setter方法注入
此处以brand业务层举例,调用数据传输mapper层
1. 变量(接口)注入
@Service
public class BrandServiceImpl implements IBrandService {
@Autowired
private BrandMapper brandMapper;
}
2. 构造器注入
@Service
public class BrandServiceImpl implements IBrandService {
private final BrandMapper brandMapper;
public BrandServiceImpl(BrandMapper brandMapper){
this.brandMapper = brandMapper;
}
}
3. setter方法注入
@Service
public class BrandServiceImpl implements IBrandService {
private BrandMapper brandMapper;
@Autowired
public void setBrandMapper(BrandMapper brandMapper){
this.brandMapper = brandMapper;
}
}
优缺点:
变量注入:{
优点:注入方式简单简洁没有多余的代码。
缺点:可能会导致循环依赖问题,当调用的bean有问题时,启动时不会报错,只有在使用到那个bean时才会报 错;
根据这种方式注入依赖的类过于依赖IOC容器,一旦脱离容器就无法实例化。换而言之,不能通过new方 式创建该类的实例,因为该类中的依赖需要IOC来注入。
}
构造器注入:{
优点:显式注明必须强制注入,通过强制指明依赖注入来保证这个类的运行,防止发生NullPointerException;
注入的对象可以使用final;
可以避免循环依赖问题,如果存在循环依赖问题,spring在项目启动时就会报错。
缺点:当有多个对象或者更多需要注入时,构造器就会显得很臃肿,可读性差。
}
setter方法注入:{
优点:依赖注入使用的依赖对象是可选的,即可以为null值
允许在类构造完成后重新注入 ,即能够通过懒加载的方式解决循环依赖
缺点:注入的对象不能用final修饰,即setter注入的依赖不能保证依赖不可变。
}
总结:
最不推荐使用的是变量注入,除了省力以外没有好处。官方不建议使用
setter注入和构造器注入各有优劣,需要根据实际情况选择。需要保证注入依赖的可靠性或者该注入的属性是必选的就用构造器注入,需要保留注入依赖的灵活性就用setter注入。