浅谈Spring设计(一)

2年前 (2022) 程序员胖胖胖虎阿
115 0 0

总概

最近一直在思考Spring的设计,从这个角度去思考这个框架,并且散发考虑其他Spring的生态。而Spring的基础就是Bean的生命周期的管理,由此去合并AOP的功能,同时还有配置的管理,事件监听的管理,还有MessageSource的管理,还有资源的管理,等等散发开来。我们先从Spring的Bean的生命周期这个角度去思考Spring的设计。

Spring容器生命周期

我们在思考Spring的Bean的生命周期之前需要站在更上一层,Spring的容器生命周期去考虑才能有一个完整的大局观。说到这个大局观,我们需要对Spring的容器的接口定义需要熟悉一下,同时也需要熟悉一下接口的实现的骨架,最后面去关注核心的几点,聚集理解Spring的Bean生命周期。

Bean的生命周期我们需要从这个角度去考虑,首先我们需要将Bean进行配置化,可以通过配置去修改Bean的值,所以我们需要构建好Environment。之后我们需要把Bean的定义按照规则发现扫描,然后存储起来供后期实例化Bean使用。最后我们开始Bean的生命周期的流转,而对于一个框架来说需要对每一步可以提供可以拓展的接口,包括实例化前后,初始化前后,以此可以更好拓展Bean的管理,以及可以供第三方接入Bean管理。

Spring的容器接口

浅谈Spring设计(一)
我们这里做一些简单的介绍。首先是和我们生产使用相关的是
web相关接口:ConfigurableWebApplicationContext和WebApplicationContext。
核心接口:

  1. EnvironmentCapable:提供获取Environment接口
  2. ListableBeanFactory/BeanFactory:提供Bean依赖查找。

    至于其他的接口不是我们聚焦的核心,可以自行查看。

Spring的容器实现

我们以更多使用的java配置web容器相关的一个具体实现举例:AnnotationConfigWebApplicationContext
浅谈Spring设计(一)
对于使用模板方法设计模式熟悉的小伙伴,一定比较熟悉这类写法,而我们主要的方法的核心实现在AbstractApplicationContext#refresh方法,该方法就是容器启动的生命周期,包括如下:

  1. 准备Environment
  2. 获取刷新之后的BeanFactory
  3. 准备实例化之后的BeanFactory
  4. BeanFactory的后置处理拓展方法
  5. 执行BeanFactory的后置处理器BeanFactoryPostProcessor。这里面其中就有是BeanDefinition的扫描的拓展
  6. 注册Bean的后置处理器BeanPostProcessor。这里面更多是一些依赖注入的后置处理器
  7. 初始化messageSource
  8. 初始化事件广播器,用于事件监听器
  9. onRefresh拓展方法
  10. 注册监听器
  11. 完成BeanFactory的初始化。这里面有Bean的生命周期的管理
  12. 完成刷新

Spring的生命核心

我们会去除一些监听器管理和资源管理等等这些其他功能的管理,以此更加聚焦的考虑Bean的生命周期。去除之后的核心的容器的生命周期核心为以下几点:

  1. Environment的管理
  2. BeanDefinition的管理
  3. Bean的生命周期

Environment管理

把Environment领出来是因为我们在加载BeanDefinition的时候需要这些配置,这一块的拓展也可以结合我们配置中心加以举例。

BeanDefinition管理

而对于BeanDefinition的管理,我们以Java配置进行举例。BeanDefinition的管理接口是BeanDefinitionRegistry,会将BeanDefinition存储在容器内,供后期管理Bean的生命周期使用。
那么进一步去了解BeanDefinition的管理,我们需要了解触发条件的管理,其中这些是由BeanFactory的后置处理器进行拓展控制,主要是以下步骤:

  1. BeanFactory的后置处理器ConfigurationClassPostProcessor的加载
  2. BeanFactory的后置处理器ConfigurationClassPostProcessor的执行
  3. BeanDefinition的扫描
  4. BeanDefinition的注册
加载

ConfigurationClassPostProcessor的加载是在获取刷新BeanFactory已经注册作为BeanDefinition的定义

执行

ConfigurationClassPostProcessor的执行也是在容器执行BeanFactory的后置处理器会根据之前加载的后置处理器的BeanDefinition进行实例化,加载到容器内部,然后执行

扫描

BeanDefinition的扫描,首先是从BeanDefinition的名字进行判断里面的@Configuration的定义。然后使用ConfigurationClassParser#parse解析@Configuration配置的类,将里面的注解进一步解析包括@PropertySources、@ComponentScan、@ComponentScans、@Import、@ImportResource、@Bean

注册

ConfigurationClassParser解析配置类的注解收集好信息,进一步使用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions进行注册BeanDefinition

Bean的生命周期

之前我们扫描完BeanDefinition之后,然后就可以进行Bean的整个生命过程,而Bean的生命开始一般都是走依赖查找的方法AbstractBeanFactory#doGetBean,我们以单例为例子,其他scope不进行赘述,主要有以下步骤:

  1. 从单例缓存中获取,同时对FactoryBean进行处理
  2. 从父容器进行依赖查找
  3. 对Bean的DependsOn有优先级需要依赖的Bean先依赖查找
  4. 单例进行实例化前置处理的拓展执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation如果返回不为null的实例,则不进行往下执行
  5. 根据反射进行实例化
  6. 执行合并BeanDefinition,执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
  7. 如果允许循环依赖,则先存储Bean实例化的Factory,用于循环依赖执行获取早期的Bean
  8. 填充Bean,进行执行实例化之后的后置处理器,InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
  9. 填充Bean,执行属性后置处理器,InstantiationAwareBeanPostProcessor#postProcessProperties
  10. 初始化Bean,执行Aware后期处理器,比如BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
  11. 初始化Bean,初始化之前的后置处理器
  12. 初始化Bean,执行初始化方法,包括自定义
  13. 初始化Bean,初始化之后的后置处理器
  14. 将单例进行存储缓存

依赖注入

以@Resource和@Autowire举例。而这两个处理都是以BeanPostprocessor进行拓展,首先需要将需要注入的信息进行扫描,使用InjectedElement进行存储,然后根据不同的情况进行注入。

@Resource注入

使用CommonAnnotationBeanPostProcessor处理器拓展。

  1. buildResourceMetadata方法扫描该方法里面标注@Resource等注解的属性或者方法
  2. @Resource的元素的注入进行复写使用getResource-》autowireResource进行依赖查找
  3. 默认调用beanFactory.resolveBeanByName根据名字进行依赖查找
  4. 否则使用beanFactory.resolveDependency进行扫描所有的Bean的名字收集符合需要注入类型的Bean,然后根据多个首要的方式进行注入
@Autowire注入

使用AutowiredAnnotationBeanPostProcessor处理器拓展。

  1. buildAutowiringMetadata方法扫描标注了@Autowire等注解的属性或者方法
  2. @Autowire的元素的注入inject方法复写使用beanFactory.resolveDependency进行依赖查找,扫描所有符合类型,进行注入。
版权声明:程序员胖胖胖虎阿 发表于 2022年9月2日 下午12:00。
转载请注明:浅谈Spring设计(一) | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...