本文是 Spring Framework 系列的第一篇。我们首先从 IoC 的概念聊起,了解维基百科上 IoC 的五种实现方式,同步分析传统的 IoC 容器的优缺点。最后,我们进一步了解 Spring IoC 容器有上此之上做了那些改进。
1. IoC 概述
1.1 IoC 发展简介
- 1983年,Richard E. Sweet 在《The Mesa Programming Environment》中提出 “Hollywood Principle”(好莱坞原则)
- 1988年,Ralph E. Johnson & Brian Foote 在《Designing Reusable Classes》中提出 “Inversion of control”(控制反转)。
- 1996年,Michael Mattsson 在《Object-Oriented Frameworks, A survey of methodological issues》中将 “Inversion of control” 命名为 “Hollywood principle”。
- 2004年,Martin Fowler 在《Inversion of Control Containers and the Dependency Injection pattern》(中文翻译点击这里)中提出了自己对 IoC 以及 DI 的理解。
- 2005年,Martin Fowler 在《Inversion Of Control》对IoC 做出进一步的说明。
说明:实际上,无论是 IoC 还是 Hollywood Principle 都是一种外部化配置化手段,通过外部化配置来提升程序的灵活性。
1.2 IoC 主要实现策略
维基百科(https://en.wikipedia.org/wiki/Inversion_of_control)Implementation techniques 小节的定义:
In object-oriented programming, there are several basic techniques to implement inversion of control. These are:
- Using a service locator pattern(SPI)
- Using dependency injection, for example(依赖注入)
- Constructor injection(构造器注入)
- Parameter injection(参数注入)
- Setter injection(setter 方法注入)
- Interface injection(接口回调)
- Using a contextualized lookup(依赖查找)
- Using template method design pattern(模板方法):Servlet#init(ServletConfig)
Using strategy design pattern(策略模式)
1.3 IoC 容器的职责
依赖处理:依赖查找和依赖注入。
- 生命周期管理:容器和托管的资源(Java Beans 或其他资源)。
-
1.4 IoC 容器的实现
Java SE
- Java Beans: JDK JavaBeans 和 BeanContext
- Java ServiceLoader SPI:最典型的实现 《Dubbo SPI:简易版的 IoC 和 AOP》
- JNDI(Java Naming and Directory Interface):《Spring IOC 前世今生之 JDNI》
- Java EE
- EJB(Enterprise Java Beans)
- Servlet(eg: Tomcat、Jboss)
开源
- Apache Avalon:http://avalon.apache.org/closed.html
- PicoContainer:http://picocontainer.com/
- Google Guice:https://github.com/google/guice
- Spring Framework:https://spring.io/projects/spring-framework
2. Spring IoC
Spring IoC 实现的主要技术是依赖查找和依赖注入,这两部分其实也是整个 Spring IoC 的核心。相对传统的 IoC 容器而言,Spring IoC 提供了类型查找,和依赖注入功能。大部分场景下,Spring 都是根据类型注入,需要先获取对象类型,我称之为类型自省。另外,Spring 注解驱动和元编程都需要首先获取对象的类型,才能拿到注解信息。因此,类型自省是 Spring IoC 最基础的功能,同时也是最复杂的部分之一,因为 Spring 提供了多种 Bean 创建的方式,每种创建方式获取其类型的方法也不一样。正因为 Spring IoC 成功的解决类型自省的问题,才有 Spring Boot 注解驱动和元编程的流行。2.1 Spring IoC 依赖查找
根据名称查找:getBean(String)
- 根据类型查找:getBean(Class)
- 根据名称 + 类型查找:getBean(String, Class)
根据注解查找:getBeansWithAnnotation(Component.class)
2.2 Spring IoC 依赖注入
根据名称注入:getBean(String)
根据类型注入:resolveDependency(DependencyDescriptor, String)
2.2.1 注入模式
手动模式只会按照配置的规则(名称或类型注入)注入指定的字段,而自动注入则默认会将有 setter 方法的所有字段进行注入,可能会造成不必要的注入。Spring 也推荐使用手动模式进行属性注入,也是默认的注入模式。
手动模式:配置或者编程的方式,提前安排注入规则(名称或类型注入,并指定需要注入的字段)
- XML 资源配置元信息
- Java 注解配置元信息
- API 配置元信息
自动模式:实现方提供依赖自动关联的方式,按照內建的注入规则
实时注入:实例化时进行注入。
-
2.3 Spring IoC 依赖来源
自定义 Bean
- 容器內建 Bean 对象
-
2.4 Spring IoC 容器
BeanFactory 是 Spring 底层 IoC 容器。
- ApplicationContext 是具备应用特性的 BeanFactory 超集。
ApplicationContext 除了IoC 容器角色,还有提供:
- 面向切面(AOP)
- 配置元信息(Configuration Metadata)
- 资源管理(Resources)
- 事件(Events)
- 国际化(i18n)
- 注解(Annotations)
- Environment 抽象(Environment Abstraction)
3. 总结时刻
本小节讲了两部分内容:IoC 的基本概念和 Spring IoC 的演进。
IoC 一般包括 SPI、依赖查找、依赖注入、模板方法、策略模式五种实现方案。其中依赖注入又可以分为构造器注入、参数注入、字段注入、接口回调等。
Spring IoC 实现的主要技术是依赖查找和依赖注入。依赖查找提供了根据名称、类型或注解三种查找方式。依赖注入内部实际上也需要进行依赖查找。推荐阅读
- 《Dubbo SPI:简易版的 IoC 和 AOP》:SPI 实现 IoC。
- 《Spring IOC 前世今生之 JDNI》:Tomcat JDNI。
每天用心记录一点点。内容也许不重要,但习惯很重要!