设计模式实战:自定义SpringIOC(理论分析)
自定义SpringIOC(理论分析)
上一篇:设计模式开源实战:观察者模式不知道怎么用?手撕Spring源码中跟着大佬学编程
上一篇我们研究了大佬在Spring源码中使用的观察者模式,今天我们再来聊聊Spring的核心功能——Sping IOC容器,最终我们跟着大佬的思路实现一个属于自己的IOC容器!Start Go!
Spring IOC核心组件
1) BeanFactory
BeanFactory作为最顶层的一个接口,定义了IoC容器的基本功能规范。
从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory
,它实现了所有的接口。那么为何要定义这么多层次的接口呢?
每个接口都有它的使用场合,主要是为了区分在 Spring 内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。
例如,
ListableBeanFactory
接口表示这些 Bean 可列表化。HierarchicalBeanFactory
表示这些 Bean 是有继承关系的,也就是每个 Bean 可能有父 BeanAutowireCapableBeanFactory
接口定义 Bean 的自动装配规则。
这三个接口共同定义了 Bean 的集合、Bean 之间的关系及 Bean 行为。
在 BeanFactory 里只对 IOC 容器的基本行为做了定义,根本不关心你的 Bean 是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。
2 ) ApplicationContext
BeanFactory 有一个很重要的子接口,就是 ApplicationContext 接口,该接口主要来规范容器中的 bean 对象是非延时加载,即在创建容器对象的时候就对象 bean 进行初始化,并存储到一个容器中。
//延时加载
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("bean.xml"));//立即加载
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
ApplicationContext 的子类主要包含两个方面:
-
ConfigurableApplicationContext 表示该 Context 是可修改的,也就是在构建 Context 中用户可以动态添加或修改已有的配置信息
-
WebApplicationContext 顾名思义,就是为 web 准备的 Context 他可以直接访问到 ServletContext,通常情况下,这个接口使用少
要知道工厂是如何产生对象的,我们需要看具体的 IOC 容器的实现,Spring 提供了许多 IOC 容器实现,比如:
- ClasspathXmlApplicationContext : 根据类路径加载 xml 配置文件,并创建 IOC 容器对象。
- FileSystemXmlApplicationContext :根据系统路径加载 xml 配置文件,并创建 IOC 容器对象。
- AnnotationConfigApplicationContext :加载注解类配置,并创建 IOC 容器。
总体来说 ApplicationContext 必须要完成以下几件事。
- 标识一个应用环境
- 利用 BeanFactory 创建 Bean 对象
- 保存对象关系表
- 能够捕获各种事件
3) Bean定义:BeanDefinition
这里的 BeanDefinition 就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {//DefaultListableBeanFactory 中使用 Map 结构保存所有的 BeanDefinition 信息private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
}
BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。
4) BeanDefinitionReader
Bean 解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean的解析主要就是对 Spring 配置文件的解析。
这个解析过程主要通过 BeanDefinitionReader 来完成,看看 Spring 中 BeanDefinitionReader 的类结构图,如下图所示。
BeanDefinitionReader 接口定义的功能
public interface BeanDefinitionReader {/*下面的loadBeanDefinitions都是加载bean定义,从指定的资源中*/int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
5) BeanFactory后置处理器
后置处理器是一种拓展机制,贯穿Spring Bean的生命周期
后置处理器分为两类:
BeanFactory后置处理器:BeanFactoryPostProcessor
实现该接口,可以在spring的bean创建之前,修改bean的定义属性
public interface BeanFactoryPostProcessor {/** 该接口只有一个方法postProcessBeanFactory,方法参数是ConfigurableListableBeanFactory,通过该参数,可以获取BeanDefinition*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
6) Bean后置处理器:BeanPostProcessor
BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口
实现该接口,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些处理逻辑
public interface BeanPostProcessor {//bean初始化方法调用前被调用Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;//bean初始化方法调用后被调用Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
IOC流程图
- 容器环境的初始化(系统、JVM 、解析器、类加载器等等)
- Bean 工厂的初始化( IOC 容器首先会销毁旧工厂,旧 Bean 、创建新的工厂)
- 读取:通过 BeanDefinitonReader 读取我们项目中的配置(application.xml)
- 定义:通过解析 xml 文件内容,将里面的 Bean 解析成 BeanDefinition(未实例化、未初始化)
- 将解析得到的 BeanDefinition ,存储到工厂类的Map容器中
- 调用 BeanFactoryPostProcessor 该方法是一种功能增强,可以在这个步骤对已经完成初始化的 BeanFactory 进行属性覆盖,或是修改已经注册到 BeanFactory 的 BeanDefinition
- 通过反射实例化 bean 对象
- 进入到 Bean 实例化流程,首先设置对象属性
- 检查 Aware 相关接口,并设置相关依赖
- 前置处理器,执行 BeanPostProcesser 的before 方法对 bean 进行扩展
- 检查是否有实现 initializingBean 回调接口,如果实现就要回调其中的 AftpropertiesSet() 方法,(通过可以完成一些配置的加载)
- 检查是否有配置自定义的 init-method ,
- 后置处理器执行 BeanPostProcesser 的after 方法 --> AOP 就是在这个阶段完成的, 在这里判断 bean 对象是否实现接口,实现就使用 JDK 代理,否则选择 CGLIB
- 对象创建完成,添加到BeanFactory的单例池中。
往期回顾
设计模式开源实战:观察者模式不知道怎么用?手撕Spring源码中跟着大佬学编程
设计模式开源实战:大佬是怎么使用工厂模式的?来看看Spring中工厂模式的应用就知道了