IoC容器
容器是一种为某种特定组件的运行提供必要支持的一个软件环境
通常来说,使用容器运行组件,除了提供一个组件运行环境之外,容器还提供了许多底层服务。例如,Servlet容器底层实现了TCP连接,解析HTTP协议等非常复杂的服务
Spring的核心就是提供了一个IoC容器,它可以管理所有轻量级的JavaBean组件,提供的底层服务包括组件的生命周期管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等
主要介绍Spring容器如何对组件进行生命周期管理和配置组装服务
IoC原理
不直接new一个DataSource,而是注入一个DataSource,这个小小的改动虽然简单,却带来了一系列好处:
BookService不再关心如何创建DataSource,因此,不必编写读取数据库配置之类的代码;DataSource实例被注入到BookService,同样也可以注入到UserService,因此,共享一个组件非常简单;- 测试
BookService更容易,因为注入的是DataSource,可以使用内存数据库,而不是真实的MySQL配置。 因此,IoC又称为依赖注入(DI:Dependency Injection),它解决了一个最主要的问题:将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。
依赖注入方式
Spring的IoC容器同时支持属性注入和构造方法注入,并允许混合使用。
无侵入容器
在设计上,Spring的IoC容器是一个高度可扩展的无侵入容器。所谓无侵入,是指应用程序的组件无需实现Spring的特定接口,或者说,组件根本不知道自己在Spring的容器中运行。这种无侵入的设计有以下好处:
- 应用程序组件既可以在Spring的IoC容器中运行,也可以自己编写代码自行组装配置;
- 测试的时候并不依赖Spring容器,可单独进行测试,大大提高了开发效率。
使用Annotation配置
使用Annotation配合自动扫描能大幅简化Spring的配置,我们只需要保证:
- 每个Bean被标注为
@Component并正确使用@Autowired注入; - 配置类被标注为
@Configuration和@ComponentScan; - 所有Bean均在指定包以及子包内。
定制Bean
Scope
容器都返回一个新的实例,这种Bean称为Prototype(原型),它的生命周期显然和Singleton不同。声明一个Prototype的Bean时,需要添加一个额外的@Scope注解:
注入List
要指定List中Bean的顺序,可以加上@Order注解:
可选注入
默认情况下,当我们标记了一个@Autowired后,Spring如果没有找到对应类型的Bean,它会抛出NoSuchBeanDefinitionException异常。
可以给@Autowired增加一个required = false的参数:
@Component
public class MailService {
@Autowired(required = false)
ZoneId zoneId = ZoneId.systemDefault();
...
}
创建第三方Bean
如果一个Bean不在我们自己的package管理之类,例如ZoneId,如何创建它?
答案是我们自己在@Configuration类中编写一个Java方法创建并返回它,注意给方法标记一个@Bean注解:
初始化和销毁
在Bean的初始化和清理方法上标记@PostConstruct和@PreDestroy:
Spring容器会对上述Bean做如下初始化流程:
- 调用构造方法创建
MailService实例; - 根据
@Autowired进行注入; - 调用标记有
@PostConstruct的init()方法进行初始化。
而销毁时,容器会首先调用标记有@PreDestroy的shutdown()方法。
使用别名
相同类型的Bean只能有一个指定为@Primary,其他必须用@Quanlifier("beanName")指定别名;
注入时,可通过别名@Quanlifier("beanName")指定某个Bean。
使用Resource
Spring提供了一个org.springframework.core.io.Resource(注意不是javax.annotation.Resource),它可以像String、int一样使用@Value注入:
注入配置
Spring容器看到@PropertySource("app.properties")注解后,自动读取这个配置文件,然后,我们使用@Value正常注入:
复制代码
@Value("${app.zone:Z}")String zoneId;
使用条件装配
Spring允许通过@Profile配置不同的Bean;
Spring还提供了@Conditional来进行条件装配,Spring Boot在此基础上进一步提供了基于配置、Class、Bean等条件进行装配。