1. What 什么是IoC
IoC全称Inversion of Control,直译为控制反转。
2. Why 为什么使用
我们假定一个在线书店,通过BookService获取书籍:
public class BookService {private HikariConfig config = new HikariConfig();private DataSource dataSource = new HikariDataSource(config);public Book getBook(long bookId) {try (Connection conn = dataSource.getConnection()) {...return book;}}
}
为了从数据库查询书籍,BookService持有一个DataSource。为了实例化一个HikariDataSource,又不得不实例化一个HikariConfig。
从上面的例子可以看出,如果一个系统有大量的组件,其生命周期和相互之间的依赖关系如果由组件自身来维护,不但大大增加了系统的复杂度,而且会导致组件之间极为紧密的耦合,继而给测试和维护带来了极大的困难。
因此,核心问题是:
- 谁负责创建组件?
- 谁负责根据依赖关系组装组件?
- 销毁时,如何按依赖顺序正确销毁?
解决这一问题的核心方案就是IoC。
3. HOW 怎么实现
在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。为了能让组件在IoC容器中被“装配”出来,需要某种“注入”机制,例如,BookService自己并不会创建DataSource,而是等待外部通过setDataSource()方法来注入一个DataSource:
public class BookService {private DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}
}
在正常情况下,我们有两种方式实现依赖注入,1、使用构造方法;2、使用 Setter() 方法。一般使用构造方法(因为依赖可能有多个):
因为 Spring 实现了依赖注入,所以我们程序员没有了创建对象的控制权,所以也被称为控制反转(Inversion of Control,简称 IoC)。因为 Spring 使用 Map 管理 BeanDefinition,我们也可以将 Spring 称为 IoC 容器。
在业务开发中,如果每个业务类均设置构造函数,并且需要在 xml 中配置,那么就太繁琐,还容易出错。Spring 从 2.5ref 开始,新增了注解,可以使用注解来替代业务类的 xml 配置和构造函数。
- 使用 @Component 注解代替
<bean> - 使用 @Autowired 注解代替
<constructor-arg>+ 构造函数。
@Component
public class BookService {@Autowiredprivate DataSource dataSource;
}
Spring 的原理离不开两个关键词:反射和注解。
- 反射:在创建 Bean 实例和依赖注入是都需要使用反射。
- 注解:使用注解可大大提升代码可阅读性,降低复杂度。注解本质上是作为一个标识,获取注解时需要使用字节码技术。
现在我们一般很少使用 xml 来设置 bean,但了解了 xml 可以更好的理解 Spring 注解的原理。
- @Component 作为组件标识,代表需要 Spring 管理
- @Autowired 用于判断是否需要依赖注入,代替构造函数
- @ComponentScan 指定组件扫描路径,不指定即为当前路径
- @Configuration 代表配置类,作为 Spring 寻找需要被管理 Bean 的入口
- @Bean 实现将任意 Bean 注入容器
- @EnableAutoConfiguration 实现自动加载配置类到容器