如果你想不费太多脑筋认识spring,你只需要记住,spring=IOC+AOP就好,其他的都是附带的工程化优化。
为什么我们需要IOC,上一节已经讲过了 juejin.cn/post/764125...
如果只能给我一句话,来说明spring是如何实现IOC的,我会回答:
框架创建一个对象,专用于管理业务中的组件。
所谓的组件,就是进行业务工作的对象,例如我们的controller,service这些bean。
而这个管理者对象,就是我们所说的容器。
而所谓的管理工作,就是创建对象,实现依赖关系,操作组件的生命周期。
容器原始接口BeanFactory
BeanFactory是一个接口,它定义了容器的本源工作,也是最高层级的接口。
arduino
public interface BeanFactory
{
// 根据名称拿Bean
Object getBean(String name);
// 根据名称+类型拿Bean <T>
T getBean(String name, Class<T> requiredType);
// 判断是否存在
Bean boolean containsBean(String name);
// 判断是否单例
boolean isSingleton(String name);
}
可以看到,根源的容器接口,主要做的,就是获取bean。
这也描绘了它的主要使命------解耦,容器的本质功能,就是1把bean传递给需要的人,而不是对象们自行创建和寻找bean。
但是,光获取bean的功能是远远不够的。bean的实例化,依赖注入,生命周期,肯定也需要实现,于是乎,一层层的抽象出来了。
最开始的时候,我们使用的是XmlBeanFactory这个实现类。
它是经过了一系列的功能扩充。
接口继承链
BeanFactory
├─HierarchicalBeanFactory 父子容器规范
├─ListableBeanFactory 批量查询规范
└─AutowireCapableBeanFactory 装配生命周期规范
↓ ConfigurableBeanFactory 可配置规范
↓ ConfigurableListableBeanFactory 集齐所有BeanFactory规范
类继承链
DefaultSingletonBeanRegistry 单例缓存实现
↓ FactoryBeanRegistrySupport FactoryBean处理实现
↓ AbstractBeanFactory 实现BeanFactory基础逻辑
↓ AbstractAutowireCapableBeanFactory 实现创建+注入+生命周期
↓ DefaultListableBeanFactory 实现BeanDefinition注册+全能力落地
↓ XmlBeanFactory 继承所有底层实现,再加XML解析
XmlBeanFactory的核心功能便是加载XML 配置,把标签转化为内存中的bean。并且继承父类能力,管理bean的生命周期。
- 单例 Bean 缓存
- 依赖注入
- Bean 实例创建
- 三级缓存解决循环依赖
- Bean 别名、作用域管理
而它早已被淘汰,也不是当今我们的主角。
容器的进化ApplicationContext
在框架的工作中,渐渐发现许多的工作常用,但是XmlBeanFactory却处理不了,例如
- 无容器事件发布
- 无国际化 i18n
- 无统一资源加载
- 无环境变量配置
- 不会自动执行 BeanPostProcessor
- 不支持预加载 Bean,错误发现晚
- 不整合 AOP、事务等企业级功能
而这一切,在ApplicationContext中实现了。
javascript
ApplicationContext (org.springframework.context)
├─ EnvironmentCapable
│ └─ 核心能力:获取/管理环境配置(配置文件、系统变量、profile)
│
├─ ListableBeanFactory
│ ├─ BeanFactory
│ │ └─ 核心能力:最基础的IoC容器规范(getBean、判断单例/存在)
│ └─ 核心能力:批量获取Bean、按类型/注解查询Bean、获取Bean定义元数据
│
├─ HierarchicalBeanFactory
│ ├─ BeanFactory
│ │ └─ 核心能力:同上
│ └─ 核心能力:支持父子容器层级结构、区分本地/父容器Bean
│
├─ MessageSource
│ └─ 核心能力:国际化消息支持(多语言文本)
│
├─ ApplicationEventPublisher
│ └─ 核心能力:容器事件发布(如容器启动、刷新事件)
│
└─ ResourcePatternResolver
├─ ResourceLoader
│ └─ 核心能力:统一资源加载(classpath:/、file:/等协议)
└─ 核心能力:支持Ant风格路径匹配的资源批量加载
根据继承图,我们可以看到,这个接口有多么强大的功能,在普通的IOC管理之外,还有一系列的工程能力,例如国际化,统一资源加载,环境配置等等。
而我们平时常用的springboot项目,其容器也是这个接口的间接实现类------AnnotationConfigServletWebServerApplicationContext。
说它间接,是因为中间又隔了很多层的继承。
但是为什么我们平时聊得更多的是ApplicationContext而不是AnnotationConfigServletWebServerApplicationContext呢?
因为ApplicationContext这个层面,已经定义好了所有容器需要对外的能力,到达这个层次,容器就齐活儿了。
而更多的继承,本质是扩展更多的细节功能,或者特殊场景(例如无 Web 环境GenericApplicationContext)。
我们可以看到,容器的继承关系,是学习面向对象的"继承"思想的典型案例。
spring框架的价值,绝大部分就在ApplicationConetxt这个容器身上了,要搞懂spring,只需要去挖掘它即可。
容器的根基功能就是:
- IoC 控制反转。把对象创建、依赖管理全部交给容器,程序员不用
new对象,彻底解耦。 - DI 依赖注入。容器自动装配属性、自动维护依赖关系,解决项目最头疼的对象耦合问题。
- 容器统一托管全组件。所有
@Controller / @Service / @Mapper / @Component全由容器统一初始化、管理生命周期。
目前spring已经借助容器帮我们实现了业务代码的解耦,其余的所有功能AOP、事务、配置环境、事件监听、整合三方插件,全部都依赖于IOC的根基。
那么,容器具体是如何将这些业务对象,转换为乖巧的bean,并且治理得有模有样的?下一节,我们来解析,bean,在spring框架中,到底是个什么样的存在,以及它是如何参与到框架工作,它身上又有哪些可以挖掘的地方(非常重要!)。