首先来看看 Spring 中的实例该如何注入,总结起来,无非三种:
- 属性注入
- set 方法注入
- 构造方法注入
我们分别来看下。
1、属性注入
属性注入是大家最为常见也是使用最多的一种注入方式了,代码如下:
@Service
public class BService {
@Autowired
AService aService;
//...
}
不光 @Autowired 可以实现注入,@Resouce 和 @inject 也是可以实现注入的
但不知道大家有没有发现在 idea 中 使用这种注入方式会有 一个警告,即 Field injection is not recommended (不推荐注入!)
属性注入其实有一个显而易见的缺点,那就是对于 IOC 容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。因为该类没有提供该属性的 set方法或者相应的构造方法来完成该属性的初始化。换言之,要是使用属性注入,那么你这个类就只能在 IOC 容器中使用,要是想自己 new 一下这个类的对象,那么相关的依赖无法完成注入。
2、set 方法注入 (spring3.0时 推荐)
set 方法注入太过于臃肿,实际上很少使用:
@Service
public class BService {
AService aService;
@Autowired
public void setaService(AService aService) {
this.aService = aService;
}
}
Spring 团队通常提倡 setter注入,因为当属性特别多的时候,构造方法看起来会特别臃肿,特别是当属性是可选的时(属性可选意味着没必要通过构造方法注入)。Setter方法注入还有一个好处就是可以使该类的属性可以在以后重新配置或重新注入。
3、构造方法注入 (spring4.0时 推荐)
@Service
public class AService {
BService bService;
@Autowired
public AService(BService bService) {
this.bService = bService;
}
}
如果类只有一个构造方法,那么 @Autowired 注解可以省略;如果类中有多个构造方法,那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。
通过构造方法注入的方式,能够保证注入的组件不可变,并且能够确保需要的依赖不为空。此外,构造方法注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。
上面这段话主要说了三件事:
- 依赖不可变:这个好理解,通过构造方法注入依赖,在对象创建的时候就要注入依赖,一旦对象创建成功,以后就只能使用注入的依赖而无法修改了,这就是依赖不可变(通过 set 方法注入将来还能通过 set 方法修改)。
- 依赖不为空:通过构造方法注入的时候,会自动检查注入的对象是否为空,如果为空,则注入失败;如果不为空,才会注入成功。
- 完全初始化:由于获取到了依赖对象(这个依赖对象是初始化之后的),并且调用了要初始化组件的构造方法,因此最终拿到的就是完全初始化的对象了。