# spring-my-mind **Repository Path**: wang-tianqi/spring-my-mind ## Basic Information - **Project Name**: spring-my-mind - **Description**: 根据spring实现一个相对完整的IOC容器(学习为主) - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-10-27 - **Last Updated**: 2021-12-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 总结 整完spring也有一个星期了, 但是今天再回顾发现有些内容已经是有些淡忘了, 所以还是要从头到尾的过一遍, 写个小总结, 便于后面回忆. 另外, 我认为, 学习这个简化spring的目的是为了更好的认识完整的spring, 所以这次总结可能会以完整spring为基础, 并对比此项目的简化点. 此次总结会以主要模块为分层, 从接口层面或抽象类层面入手, 描述各个类的职责以及内部的逻辑流程, 不关心具体地实现. 话不多说, 直接开始. ## Factory ### 基本功能 先明确`Factory`的基本功能, 后面会将这些功能对应相应的接口. 1. 定义Bean 2. 创建Bean 3. 获取Bean 4. 保存单例Bean 5. 销毁单例Bean #### 定义Bean 一共涉及三个核心接口 ##### BeanDefinition 肯定很快能想到`BeanDefinition`. 没错, 就是常说的Bean定义. 它几乎是所有Bean的基础. 在学习spring时, 我们所有人都会听到这样的观点: 项目需要松耦合, 要面向接口编程, 不要在业务代码中使用`new`关键字. 作为初学者的我不由的发出疑问: 不使用`new`跟代码解耦有必然的联系吗? 其实面向接口编程就已经包含了不能使用`new`关键字, 因为接口中不包含构造方法, 自然无法使用`new`关键字. 那么我应该如何获取一个对象呢? **反射** 先说反射, 借助反射我可以完全不依赖某一个类而去获取某个类的一个对象, 我只需要知道它的全限定类名的字符串. 这为面向接口编程提供了可能性, 因为对象是可以自动向上转型的. 之前的两个业务类通过`new`依赖了对方的具体实现, 这就叫强耦合. 但是有了反射, 我们可以加一个中间层, 中间层负责通过反射生产接口实现类的对象, 这时候两个业务类就可以依赖接口类型, 通过中间层获取接口类型的实现类对象, 实现了松耦合. 并且因为使用了反射, 中间层也没有耦合具体的实现类, 中间层与业务也是松耦合的, 完美. 所以, spring中使用`BeanDefinition`保存Bean的描述, 根据Bean定义通过反射创建Bean. (当然还有Cglib的方式, 这里先不阐述) ##### BeanDefinitionReader 一般用户不希望了解中间件的具体逻辑, 他们只关心业务代码, 所以需要尽可能简便的操作. 所以自然不可能让用户自己去创建`BeanDefinition`. spring提供了使用配置文件的方式供用户选择, 那么就需要解析这些东西. `BeanDefinitionReader`负责解析配置文件, 并生成`BeanDefinition`. 将生成的`BeanDefinition`注册到仓库中保存起来, 便于下一步使用. ##### BeanDefinitionRegistry 这个就很好理解了`BeanDefinition`仓库, 所有的Bean定义解析完成后会注册到这个仓库里. #### 创建Bean/获取Bean ##### BeanFactory 这是所有Bean工厂的顶层接口, 定义了Bean工厂的核心功能, 就是根据Bean名称获取一个Bean对象. 它还有很多子接口, 丰富了`BeanFactory`的功能 - **ListableBeanFactory**: 提供了获取所有Bean列表的方法, 而不是一个一个获取 - **HierarchicalBeanFactory**: 分层Bean工厂, 提供了获取父工厂的方法 - **ConfigurableBeanFactory**: 提供了配置工厂的方法, 主要提供修改配置项的方法 - **AutowireCapableBeanFactory**: 提供了自动装配Bean的方法, 例如非常熟悉的`createBean`和`initializeBean`等 - **ConfigurableListableBeanFactory**: 它继承了所有工厂的方法, 是`BeanFactory`中功能最完整的接口, 并新增了一些工具方法 ![image-20211208085831221](./img/image-20211208085831221.png) ##### 创建Bean的流程 虽然在这里不讨论具体实现, 但是可以清晰一下创建Bean的大致流程, 以及一些相关的接口. 完整的创建Bean的流程在`AbstractAutowireCapableBeanFactory`的`doCreateBean`方法中. 整个流程分为五个部分 1. 实例化Bean(Instantiate the bean.) - **InstantiationStrategy** 实例化策略接口, 提供实例化Bean的方法. 使用了策略模式, 封装了两个策略. 1. 反射实例化 2. Cglib实例化 这里使用了`CglibSubclassingInstantiationStrategy`实例, 它是`SimpleInstantiationStrategy`的子类, 拥有`SimpleInstantiationStrategy`的所有方法. 除当bean定义中含有`MethodOverrides`时才使用`cglib`生成bean, 除此之外的所有情况都是用反射实例化Bean. 2. 允许后处理器修改合并的 bean 定义(Allow post-processors to modify the merged bean definition.) - **MergedBeanDefinitionPostProcessor** 继承自顶层接口`BeanPostProcessor`, 就在这简单说说顶层接口吧 **BeanPostProcessor** 这是一个钩子方法, 目的就是在创建Bean的过程中对Bean进行操作, 以达到隐藏部分逻辑的目的. 例如使用代理增强代码. 它里面声明了两个方法`postProcessBeforeInitialization(初始化前)`和`postProcessAfterInitialization(初始化后)`. 除了这两个节点, 它还有很多子接口, 例如这里的`MergedBeanDefinitionPostProcessor`, 埋入了Bean生命周期的各个节点. 说回这个接口, 它是合并所有Bean定义后处理器 3. 向第三层缓存中保存Bean的工厂对象, 以解决循环依赖问题(Eagerly cache singletons to be able to resolve circular references.) - **SmartInstantiationAwareBeanPostProcessor** 在这就不多说了, 在AOP的笔记里记录的十分详细了 4. 初始化 bean 实例(Initialize the bean instance.) - **populateBean** 填充Bean属性 - **InstantiationAwareBeanPostProcessor** 实例化后填充属性前, 调用`postProcessAfterInstantiation`修改Bean的状态 - **填充属性逻辑** - **InstantiationAwareBeanPostProcessor** 填充属性完成后, 调用`postProcessProperties`可以修改`PropertyValues`,添加删除或修改属性 调用postProcessPropertyValues, 可以修改属性值 - **applyPropertyValues**应用属性值 - **initializeBean** 应用bean后处理器,所有Bean初始化都会过一遍所有后处理器 - **applyBeanPostProcessorsBeforeInitialization** 应用初始化前处理器, 这里的初始话指的是用户定义的初始化方法, 一般有两种方式定义它 实现`InitializingBean`的`afterPropertiesSet()`或者使用配置文件的`init-method`元素 - **postProcessBeforeInitialization** 初始化之前也就是调用`afterPropertiesSet`或者`init-method`前, 调用`BeanPostProcessor`的初始化前处理器 - **invokeInitMethods** 调用初始化防范也就是... - **applyBeanPostProcessorsAfterInitialization** 初始化后调用`postProcessAfterInitialization`后处理器 - **getSingleton** 在`DefaultSingletonBeanRegistry`使用三级缓存处理了循环依赖. 详细看具体笔记. 5. 注册一次性Bean(Register bean as disposable.) 一次性Bean与单例Bean不同, 分别保存在不同的容器中, 这里会通过`registerDisposableBean`保存`DisposableBeanAdapter`一个实例, 它是一个`Runnable`的实现类. 最终会由这些实例销毁需要销毁的Bean. #### 保存单例Bean 现在还有一个问题, 整个流程已经结束了, 那么在哪里注册的单例Bean呢? 逻辑其实在`DefaultSingletonBeanRegistry`中的`getSingleton(String beanName, ObjectFactory singletonFactory)`方法中. 可以看到这里的第二个参数是`ObjectFactory`, 调用它的位置是`AbstractBeanFactory`的`doGetBean`方法中 ```java sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); ``` 可以看到它实际传入的是`createBean`方法. 也就是说`DefaultSingletonBeanRegistry`调用了`createBean`并将返回的`SingletonBean`注册到单例Bean仓库. #### 销毁Bean **DisposableBeanAdapter** 在上面的创建Bean的流程中有一个`注册一次性Bean`的步骤, 这个所谓一次性Bean的类就是`DisposableBeanAdapter` 这个类对应每一个需要销毁的Bean, 最终的销毁工作也是由它来完成. 虽然它是一个`Runnable`的实现类, 但是在spring并没有使用线程执行它. ### Aware接口 感知接口, 这是一个标记接口, 它里面没有任何方法的声明. 它的子接口需要定义一个`set`方法, 在`spring`的流程中的某些特殊节点调用这个`set`方法, 实现让外部感知到某些特定对象的功能. 这里说几个常用的感知接口 - **BeanFactoryAware**: 获取当前类所属的Bean工厂实例 - **BeanNameAware**: 获取当前类Bean的名称 - **BeanClassLoaderAware**: 获取当前类Bean的类加载器 ## ApplicationContext 关于`ApplicationContext`与`BeanFactory`的区别 `ApplicationContext`是真正面向用户的完整应用而`BeanFactory`则是应用最核心的一部分. 这一点可以看看`ApplicationContext`的接口声明, 它不仅拥有`BeanFactory`的核心能力, 并且还拥有其没有的能力. ```java public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {} ``` 并且`ApplicationContext`组合了`BeanDefinitionReader`的功能, 让创建一个IOC容器对用户来说变成一行代码的操作. ### ApplicationContext事件监听器 一个非常实用的基于观察者模式的功能. 一些与业务无关的逻辑可以通过监听事件触发, 例如: 记录日志, 整合数据等 具体用法和实现已经在详细笔记中已经记录. ## Spring-AOP 这是在详细笔记中占比重最大的部分, 现在再整体梳理一下. 在详细笔记中的顺序是我一步一步梳理逻辑的顺序, 这次记录按照逻辑流程来总结. ### 在spring生命周期的位置 #### **SmartInstantiationAwareBeanPostProcessor** 代理的逻辑是在实现了此接口的`AbstractAutoProxyCreator`类中, 但是这里还要分两种情况. Bean是否有循环依赖的情况 1. 有: 那么`BeanFactory`向三级缓存中注册工厂, 这个工厂中调用的就是类中的`getEarlyBeanReference` 2. 没有: 那么会在Bean完全完成初始化后执行`postProcessAfterInitialization` 但是这两个方法最终调用的都是`wrapIfNecessary` #### **wrapIfNecessary** 梳理一下核心逻辑的流程 1. **getAdvicesAndAdvisorsForBean** 看方法就知道它的功能, 为Bean寻找`Advisor`列表 - **Advisor** 这是AOP的核心接口之一, 先回忆一下它的功能 ```java /** * 包含 AOP Advice(在连接点采取的操作)和确定Advice适用性的过滤器(例如Pointcut)的基本接口。 */ public interface Advisor { Advice getAdvice(); } ``` 它封装了`过滤器`, 以及`Advice`. 通过过滤器判断此Bean是否需要被代理, 确定后为Bean增强`Advice`. 2. **createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))** - 参数一/二: bean的信息, 用来匹配过滤器 - 参数三: `Advisor`列表, 其中封装着过滤器和`Advice` - 参数四: 需要被代理的Bean 逻辑完成后返回的bean就是被代理加强后的Bean了.