Spring与造车的关系





前言





哈喽,大家好,我是janker。
最近总有小伙伴提到搞点Spring相关文章,为了满足小伙伴的愿望,那么今天它来了。
说到Spring,常问的知识点,AOP、IOC、循环依赖等等等。。。那么具体这些如何串联起来的呢?下面就会结合一个造车小故事详细并形象跟大家说一说。





核心概念





下面说下本篇牵涉到的核心概念,其他没涉及到的暂时先不提。

下面每个概念都会以造车为例子。



BeanDefinition



官方解释一大堆,定制Bean的配置元信息接口诸如此类的解释。晦涩难懂,咱们就抽象叫他生产汽车零件的图纸



BeanFactory



bean工厂,主要作用是生产beanSpring本质上是一个bean工厂或者bean容器,在造车的例子中我们可以抽象的叫它生产汽车的车间



ApplicationContext



除了包含BeanFactory所有功能以外,还包含国际化、Spring中的环境等功能。在造车的例子中我们可以抽象的叫它生产汽车的工厂(这里的工厂区别于上面的BeanFactory 不仅生产、还有一些周边功能)。



BeanPostProcessor



BeanPostProcessorSpring IOC容器给我们提供的一个扩展接口。里面包含两个重要的方法,postProcessBeforeInitializationpostProcessAfterInitialization,Spring的核心拓展接口,与很多中间件结合都使用到它。在造车的例子中我们可以抽象的叫它汽车生产过程中的拓展接口,方便更换零件或者增加其他功能。



功能注解



类似@Lazy @Scope @DependsOn @Primary initMethodName等用来描述bean相关特性的注解或者字段。一般都用这些注解或者字段来描述造车图纸的功能



XXX Aware



Aware是感知的意思,顾名思义只要是实现了XXXXAware就能在本类中拿到想要的XXXX。举个例子,例如ApplicationContextAware 只要我们的类实现了ApplicationContextAware 我们就能拿到当前容器的ApplicationContext。以此类推。

其他类就不一一介绍了。





Spring启动整体流程






整体流程



咱们以AnnotationConfigApplicationContext为例,其他ApplicationContext过程部分步骤稍有不同,其他主流程类似。

  1. 构建ApplicationContext

    1. 初始化AnnotatedBeanDefinitionReader 注册注解配置处理类(创世纪类),如AutowiredAnnotationBeanPostProcessorConfigurationClassPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessorEventListenerMethodProcessorDefaultEventListenerFactory等。
    2. 初始化ClassPathBeanDefinitionScanner,设置Environment,设置ResourceLoader
  2. 扫描。扫描basePackage,注册Bean定义

  3. 刷新容器(整个过程中最重要的阶段)

    • 创建beanFactory(没有才创建、存在就获取)、

    • beanFactory中添加早期要用到的BeanPostProcessor,(ApplicationContextAwareProcessorApplicationListenerDetector等)注册一些系统相关类(系统环境、系统属性等)

    • BeanFactory后置处理,一般都是重写ApplicationContext#postProcessBeanFactory,不同的ApplicationContext添加的逻辑不太一样,一般都是添加跟ApplicationContext具体实现类相关的BeanPostProcessor处理类、忽视一些依赖接口、注册一些跟本ApplicationContext相关的类。

      AnnotationConfigApplicationContext举例,它并没有重写相关抽象方法。

    • invokeBeanFactoryPostProcessors,一句话概括调用BeanDefinitionRegistryPostProcessors,从注册表中的配置类派生进一步的bean定义

    • 注册拦截Bean创建的Bean处理器(各种BeanPostProcessor

    • initMessageSource,初始化MessageSource(国际化相关Bean

    • initApplicationEventMulticaster,初始化应用event多播器,注册ApplicationEventMulticaster(应用event事件相关)

    • 初始化Bean(非懒加载Bean)

    • 完成刷新(刷新后的完成工作,cache清除、注册一些必要的Bean(LifecycleProcessor)、发送刷新完成事件、)

    1. 准备刷新 (初始化属性源、校验一些必填属性)

    2. 准备beanFactory

初始化(创建)Bean过程有很多子流程,简单概括一下:

  1. 获取bean。上来就从缓存中拿Bean,存在就返回、不存在就看下这个bean是否正在创建。(使用一、二、三级缓存解决循环依赖问题)

  2. 创建bean(doCreateBean)。

    1. 在创建bean之前有相应的拓展点(对应接口InstantiationAwareBeanPostProcessor,拓展方法为postProcessBeforeInstantiation),在创建前,会遍历所有InstantiationAwareBeanPostProcessor的实现类,执行postProcessBeforeInstantiation方法,举例:AbstractAutoProxyCreator(AOP相关),PersistenceAnnotationBeanPostProcessor(ORM持久化相关)等
    2. 创建beanInstance过程中,调用determineConstructorsFromBeanPostProcessors方法,拓展接口为SmartInstantiationAwareBeanPostProcessor执行的拓展方法为determineCandidateConstructors。指定实例化的构造函数。
  3. 实例化bean。

    1. 实例化bean过程中,调用applyMergedBeanDefinitionPostProcessors,这里也是一个拓展点,对应接口MergedBeanDefinitionPostProcessor,调用的拓展方法为postProcessMergedBeanDefinition
    2. 实例化过程中,调用getEarlyBeanReference,这里面也是一个拓展点,对应接口为:SmartInstantiationAwareBeanPostProcessor,调用的拓展方法为getEarlyBeanReference。(解决循环引用)
  4. 属性赋值。属性赋值过程中也包含两个拓展点。

    1. 属性赋值过程中,循环遍历InstantiationAwareBeanPostProcessor的实现类,调用postProcessAfterInstantiation方法,作用可以中止赋值
    2. 属性赋值过程中,循环遍历InstantiationAwareBeanPostProcessor的实现类,调用postProcessPropertyValues方法,作用:注入属性,@Autowired注解在这里进行依赖注入。
  5. 初始化。初始化过程中包含4个可以拓展的地方。

    1. 一类是实现InitializingBean接口,调用拓展方法afterPropertiesSet来实现拓展。
    2. 一类是invokeCustomInitMethod,我们自己定义的init方法。
    3. 初始化过程中,调用invokeAwareMethods一堆Aware方法(一般都是实现Aware接口),主要是为bean设置beanNameBeanClassLoaderBeanFactory

    4. 正式初始化前,调用applyBeanPostProcessorsBeforeInitialization方法,还是老套路,遍历BeanPostProcessor的实现类,调用拓展方法postProcessBeforeInitialization

      举几个比较简单的类

      ApplicationContextAwareProcessor调用postProcessBeforeInitialization是为了执行一些Aware方法。

      InitDestroyAnnotationBeanPostProcessor实现类调用postProcessBeforeInitialization方法是为了执行@PostConstruct方法。剩下的就不一一列举了。

    5. 正式初始化方法,invokeInitMethods作用调用初始化方法(说了跟没说一样)。大致包含两类

      注意:从上面的流程我们可以得出:初始化的相关方法执行顺序如下:PostConstruct > afterPropertiesSet > 我们自己定义的初始化方法。

    6. 初始化后,调用applyBeanPostProcessorsAfterInitialization,这里也是一个拓展点,换汤不换药,拓展接口为BeanPostProcessor,调用的拓展方法为postProcessAfterInitialization,顾名思义就是在初始化完成后要执行的操作。

  6. 添加到缓存中。



小结及流程图



整体过程还是比较复杂的,其实为了简化我们的理解,我们提炼出来几个比较重要的点:

  1. 准备了一些创世纪类,相当于造车的原始车床零部件。
  2. 读取了一些bean定义,这个bean定义也有两种状态:一种是概念态(描述功能),一种是定义态(把功能转化为图纸)
  3. 准备了BeanFactory,相当于制造零件的车间,在真正开始创建对象前,可以对BeanFactory做统一的拓展,以拓展额外统一的功能
  4. 开始生产Bean,在生产bean的前期、中期、后期添加了各种拓展接口,来实现我们需要的功能。(AOP的功能我们暂时先不详细说下一篇会详细带小伙伴去看一下。)

流程图如下图所示。

Spring与造车的关系

图中九个后置处理器调用的地方是核心,spring与其他组件结合很多都是基于这些拓展点。






造车小故事





上面讲了那么多概念以及各种拓展点,还是比较晦涩,不是那么好理解。下面用一个小故事,来把整个流程串联起来,就拿假药停造车的例子来说。

  1. 贾某圈了一笔钱,买了第一个机床(创世纪类)、第一厂房(ApplicationContext)
  2. 贾某造车时的准备工作,(注册配置类、初始化操作)
  3. 贾某要想造车,必定要有一些车子基础和特有的功能,比如几座、马力、续航、智能交互,这都是概念功能阶段。
  4. 贾某手下的大将将功能转化为生产零件图纸。(功能转化为Bean定义)
  5. 拿着图纸开始造零件
  6. 造各种零件过程中,前中后开了一些拓展接口(拓展点),便于更换和DIY(更长的续航、更高的配置)。(拿钱造零件、造车)
  7. 当然造车过程中钱是少不了的,等内存紧缺的时候也就是没钱的时候自然就继续不下去。
  8. 销毁零件的过程中,也伴随着一些销毁方法,比如零件的资源再利用。

在这整个造车过程中,图纸、厂房、机床、拓展接口、钱都是少不了的,同样的BeanDefinition、ApplicationContext、创世纪类、内存也都是必不可少的。上述故事是为了让大家更好理解,也希望小伙伴结合小故事对spring有新的认识。





总结





从spring启动流程,到贾某造车,大家对spring的拓展机制以及启动过程应该有大概的认识了。针对AOP及IOC的具体实现细节将在下一节为大家呈现,敬请期待。





原文始发于微信公众号(爪哇干货分享):Spring与造车的关系

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/172022.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!