前言:Spring做为JAVA企业级应用中最为热门的框架,为开发人员提供了一系列方便易用的组件,使开发者可以集中于业务逻辑的开发,而不必关心太多底层环境的部署。我第一次接触这个框架是做校内的一个web项目,当时只是简单机械的运用了spring-boot 中的一些功能,正式开始了解框架背后的原理是今年暑假实习。一开始,我被Spring官方晦涩的文档所困住,理不清思绪,跨不出学习的第一步。
稻圣和夫曾经说过,真理之布由一根纱线织成,把事情看得越单纯,就越接近真相,也就越接近真理。一句话概括,Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。因此,我们不妨从Spring框架最核心的两个思想IOC,AOP开始,慢慢探寻框架背后的秘密。
本篇博客将以一个简单的Spring应用程序为例,介绍Spring的IOC容器启动流程
IOC容器启动步骤概括
- 定位配置文件(xml或configuration Class)
- 加载配置文件获取BeanDefinition
- 注册BeanDefinition
- 实例化Bean
简单的Spring程序
我们首先来看一个简单的HelloWorld程序,调用的我们的Renderer并渲染相应的消息
- 主程序
1
2
3
4
5
6
7
8
9public class HelloWordApplication {
public static void main(String args[]){
ApplicationContext ctx= new ClassPathXmlApplicationContext("/app-context.xml");
MessageRenderer renderer=ctx.getBean("renderer",MessageRenderer.class);
renderer.renderer();
}
}
相关接口和Bean
- 消息提供方
1 | public class HelloWordMessageProvider implements MessageProvider { |
1 | public interface MessageProvider { |
- 渲染消息方
1 | public interface MessageRenderer { |
1 | public class StandardMessageRenderer implements MessageRenderer { |
从源码分析IOC容器启动
首先我们来看一看主程序里的这一行
1 | ApplicationContext ctx= new ClassPathXmlApplicationContext("/app-context.xml"); |
短短的一行,确已经完成了IOC容器的启动,我们一会再去探寻这个构造函数到底做了什么,先来看看ApplicationContext究竟是什么
BeanFactory vs ApplicationContext
BeanFactory
BeanFactory是我们的根容器,Bean的中央注册中心,提供了依赖注入,ApplicationContext继承了BeanFactory,一般我们不会直接操作BeanFactory,而都是直接和ApplicationContext打交道
java doc上给出的BeanFactory的定义
The root interface for accessing a Spring bean container. This is the basic client view of a bean container; further interfaces such as ListableBeanFactory and ConfigurableBeanFactory are available for specific purposes.
这边给出一个例子演示一下如何直接通过BeanFactory操纵我们的Bean MessageRenderer
1 | public class XmlConfigWithBeanFactory { |
DefaultListableBeanFactory是实现了ListableBeanFactory接口的一个类
1.初始化factory
2.使用XmlBeanDefinitionReader从Xml文件读取BeanDefinition信息
3.利用我们的factory获取我们定义好的Bean
ApplicationContext
ApplicationContext是BeanFactory的扩展,除了依赖注入外,其还提供了
- Easier integration with Spring’s AOP features
- Message resource handling (for use in internationalization)
- Event publication
- Application-layer specific contexts such as the WebApplicationContext for use in web applications.
源码解析
1 | ApplicationContext ctx= new ClassPathXmlApplicationContext("/app-context.xml"); |
ClassPathXmlApplicationContext简单来说就是根据xml文件来获取我们的Bean的定义,并将Bean注册到我们的容器中
根据源码追踪我们会看到
1 | public ClassPathXmlApplicationContext(String... configLocations) throws BeansException { |
这里就是我们真正的构造函数
1 | public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException { |
- 首先我们将父容器设为null(关于父子容器这块到时候单独研究下)
- set我们的BeanDefinition
- 调用refresh(),容器启动的真正入口
容器启动的入口: refresh
源码
1 | public void refresh() throws BeansException, IllegalStateException { |
拆解一下,概括一下这个函数做的事情
graph TD A[prepareRefresh:容器启动前的准备工作]-->B[prepareBeanFactory:容器核心初始化] B-->C[invokeBeanFactoryPostProcessor:初始化BeanPostProcesor Bean] C-->D[finishBeanFactoryInitializatio:创建Singleton的Bean] D-->E[finishRefresh]
后记
就先写到这里吧:>,下一篇写一下SpringBoot启动MVC的流程吧,嗷呜,感觉给自己挖了一个大坑