Springソースコードの読み取り(1):リソースの読み込みと一般的なライフサイクル機能

概要

まず、春の一般的なアーキテクチャ図を見てみましょうimage.png

基本的なインターフェース

Resource + ResourceLoader

xmlまたはアノテーションの形式で記述した構成ファイルはすべてSpringResourceのビューのリソースでありResourceLoader、Springは記述したリソースをロードするためのリソースも提供します。

BeanFactory

まず、beanfactoryの継承関係image.pngを見てみましょう。beanFactoryのインターフェースは、Beanを取得するためのいくつかの基本的なメソッドを定義しますが、特別なことは何もありません。image.png次に

  1. HierarchicalBeanFactory

beanFactory 2の親子関係を定義するだけです。ListableBeanFactoryimage.pngの公式ドキュメントで定義されているインターフェースimage.pngは、コンテナー内のBeanをより適切にトラバースできるように設計されているため、新しく追加されたインターフェースがBean名の配列を返すこともわかります。

DefaultListableBeanFactory

上記のBeanFactoryのサブインターフェイスを確認した後、実装クラスを確認します。最初にGenericApplicationContextクラス。このクラスは、一般的に使用されるIOCコンテナの親クラスです。このクラスimage.pngにメンバー変数があることがわかります。 DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
      implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {


   bean的名称映射
   private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    
   根据类型和名称的映射
   private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

   只有单利的类和名称映射
   private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

   获得所有bean信息
   private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
复制代码

このクラスは春信息中心,包含所有bean的定义信息のものですが、彼が私たちと一緒に使用するiocコンテナーは、継承関係ではなく、組み合わせ関係です。

BeanDefinition

BeanDefinitionは、Beanのインスタンスを記述します。これは、Beanの名前、スコープ、遅延ロードされているかどうかなどのプロパティを取得できます。

BeanDefinitionRegistry

BeanDefinitionのマッピング関係を含むBeanDefinitionレジストリ

ApplicationContext

image.png 包含了很多功能,从继承接口可以看出,包含了ioc事件派发器,国际化解析,bean工厂,资源解析功能

Aware

image.png 在spring中有非常多的XXXAware,用了之后就可以获得到对象实例

BeanDefinition信息注册到BeanDefinitionRegistry流程

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Cat bean = context.getBean(Cat.class);
    System.out.println(bean);
}
复制代码

代码很简单,现在来debug看spring注册流程

  1. ClassPathXmlApplicationContext的构造方法里执行了refresh方法

image.png 2. refresh是 AbstractApplicationContext 的方法,又调用了obtainFreshBeanFactory让子类刷新内部的beanFactory image.png 3. 随后调用了 AbstractRefreshableApplicationContext类的 refreshBeanFactory方法。我们可以看到在这里创建了一个 DefaultListableBeanFactory,然后把该对象传入子类的loadBeanDefinition方法 image.png 4. 来到AbstractXmlApplicationContext类的loadBeanDefinition,根据DefaultListableBeanFactory创建了一个XMLBeanDefinitionReader然后读取配置文件 image.png 5. XMLBeanDefinitionReader的doLoadBeanDefinition方法中,根据配置文件生成Document对象然后读取 image.png 随后再创建了一个 BeanDefinitionDocumentDocumentReader,调用registerBeanDefinitions方法读取数据 image.png 6. 在BeanDefinitionDocumentDocumentReader 的内部有一个代理类,解析数据其实都是该类实现的 image.png 方法内遍历每一个节点解析数据 image.png 然后解析内部就是判断xml标签走不同的方法 image.png 7. 在解析bean的方法内部先封装了一个 BeanDefinitionHolder组合了bean的名称和BeanDefinition,然后调用一个工具类解析数据 image.png 8. 工具类内部调用 DefaultListableBeanFactory 的 方法注册Bean信息到档案馆 image.png 9. 现在正式来到DefaultListableBeanFactory内部,首先会判断这个beanName是否已经在BeanDefinitionMap中存在,如果不存在就添加到map里面,并且也会添加一个名字列表到数组中 image.png

创建单实例Bean流程

我们刚才看的是Bean的定义信息已经被保存到spring中,我们现在来看看Spring创建实体对象的流程。

  1. 还是 AbstractApplicationContext类的refresh方法,方法走到了finishBeanFactoryInitialization方法,该方法主要设置了一些beanFactory的一些参数然后调用preInstanceSingletons方法

image.png 2. 这个beanFactory就是那个DefaultListableBeanFactory,方法中通过遍历之前已经初始化好的BeanDefinitionNames,创建不是抽象,是单例,不是懒加载的对象 image.png 3. 方法来到了父类AbstractBeanFactory中的doGetBean方法中,这个方法有很多逻辑,我们先来看首次创建的逻辑 image.png 4. 做了上面一系列判断之后,调用父类DefaultSingletonBeanRegistry的getSingleton方法,方法中还会有一个回调,先不看父类的方法逻辑,直接看回调方法的createBean,这是一个抽象方法,由子类AbstractAutowireCapableBeanFactory实现 image.png 5. 执行一些暂时无意义的方法之后来到了instantiateBean方法,内部有一个创建bean的策略类,实现有jdk的反射和cglib image.png image.png 6. spring在创建bean的过程中会判断该对象是否有重写的方法,如果有的话就走gclib,没有就走jdk默认 image.png

Bean属性赋值过程

我们上面看完了Bean实例的创建过程再来看一下Bean内部的属性是如何被spring注入进来的。在AbstractAutowireCapableBeanFactorydoCreateBean方法中创建完bean实例之后继续往下执行

  1. 在doCreateBean方法内部,实例化bean后调用populateBean方法给bean属性赋值

image.png 2. 在populateBean方法中,如果是注解的方式启动的spring则会走后置处理器的方式来赋值对象,如果是xml的形式则会走另一个方法,现在大部分都是注解的方式启动的容器,所以我们直接看后置处理器的方式 image.png 3. 在初始化完bean之后spring会执行容器中的所有InstantiationAwareBeanPostProcessor对象的postProcessProperties方法,在方法中获得一个InjectionMetadata对象,该对象就有需要注入的对象和方法,后面就是直接调用invoke方法就可以了。 image.png 4. 我们再来看看spring是如何寻找@Autowire注解的,在上面方法的第一行的方法findAutowiringMetadata进去 image.png 可以看到其实返回的数据是调用buildAutowiringMetadata方法 image.png 该方法是从目标类一直循环上去,找属性是不是有目标注解 遍历集合判断是否有数据 image.png 数据的初始化就是添加这些注解 image.png

spring的后置处理器

spring提供了三种后置处理器

  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. InitializingBean

我们来依次看每个后置处理器的执行流程。

BeanFactoryPostProcessor

首先还是回到refresh方法中,我们可以看到在创建普通bean对象的上面有个方法叫invokeBeanFactoryPostProcessor,从方法名就可以看出是执行BeanFactoryPostProcessor方法 image.png 方法内部调用了一个代理类的静态方法 image.png 方法内部会首先拿出实现了PriorityOrdered接口的对象排序后执行 image.png

image.png 执行完PriorityOrdered接口后再拿出实现了Order接口的对象执行 image.png 最后把剩下的BeanFactoryPostProcessor根据类名排序后调用方法,这时候容器里面还是没有对象的,在getBean的时候需要走原来看过的创建普通bean的流程 image.png 前面的都是执行的BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry,三个判断结束之后最后执行BeanFactoryPostProcessorpostProcessBeanFactory方法 流程图如下

image.png

工厂后置增强的实际用途

我们现在知道了spring提供了一些工厂的后置处理器来增强工厂,那么我们现在来看看spring中实际使用工厂后置处理器做了什么事情,我们来看一个类ConfigurationClassPostProcessor image.png 这个类是用于处理写了@Configuratioin注解的类 image.png 排序好之后就在一个循环里面解析容器里面的类 image.png 在方法中先判断是不是需要跳过,如果写了@Conditional注解的对象会判断条件是否生效 image.png 真正解析配置类的方法里面就是各种判断注解的情况,然后去做相应的方法 image.png

BeanPostProcessor 注册

工厂的增强至此就结束了,接下来看看普通组件的后置处理器的逻辑,还是回到refresh方法,这次是调用registerBeanPostProcessors方法,注册后置处理器。 image.png 注册的逻辑跟BeanFactory都是由同一个代理类来完成的 image.png 大部分逻辑和bean工厂的逻辑一致,都是判断优先级接口的就先执行 image.png 跟bean工厂不一致的是,bean工厂的后置处理器直接执行目标方法,这里只是把bean后置处理器创建好之后就放入list中 image.png

InstantiationAwareBeanPostProcessor

所有的BeanPostProcessor都被注册之后,我们来看其中一个分支:InstantiationAwareBeanPostProcessor 的流程

SmartInstantiationAwareBeanPostProcessor

image.png 从名字上可以看出叫智能的实例后置处理器,那么这个我们就来看看智能在什么地方. 在refresh方法中调用了一个注册监听器的方法 image.png 在该方法中调用了一个根据类型获取名称列表的方法,该方法是ListableBeanFactory接口的一个方法 image.png 为了获得目标类的名称,spring遍历所有的bean的名称,一个一个判断

image.png 判断逻辑是先判断已经初始化好的实例,然后再判断bean定义信息,如果都没有则让别人来判断 image.png 拿到容器中的SmartInstantiationAwareBeanPostProcessor然后把类名和bean名称穿进去,让实现类来决定 image.png 总结流程图 image.png 所以我们知道,在spring中,根据类型来找名称其实spring需要遍历所有对象,是一件很麻烦的事情

InstantiationAwareBeanPostProcessor

image.png 在spring容器创建对象之前,会先调用 InstantiationAwareBeanPostProcessor的 postProcessBeforeInstantiation方法尝试返回对象,如果用户返回了则会用用户创建的对象。 image.png 如果没有则调用doCreateBean方法,方法内也会从一个缓存中获取,没有的话就继续调用方法创建 image.png 创建逻辑会让用户返回一个构造函数,注意这里调用的是SmartInstantiationAwareBeanPostProcessor的一个方法,如果没有就用默认的无参构造函数,之后就是上面写过的用工具类创建的方式 image.png

MergedBeanDefinitionPostProcessor

在创建好bean实例对象之后会调用一下MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法让用户定义一下BeanDefinition image.png

PopulateBean

之后就进入属性赋值方法,首先会先执行 InstantiationAwareBeanPostProcessorpostProcessAfterInstantiation方法,返回bool类型的值,如果返回true则会继续属性赋值,返回false则不会属性赋值 image.png 如果返回true则开始执行InstantiationAwareBeanPostProcessorpostProcessProperties方法。自动注入 AutowiredAnnotationBeanPostProcessor的该方法就实现了自动注入的属性赋值 image.png

PropertyValues

在上面我们可以看到postProcessProperties方法返回了一个pvs,我们也可以自定义返回pvs,spring最后会帮我们注入到对象中,创建一个PVS返回即可 image.png

BeanPostProcessor

属性赋值之后spring会执行initializeBean 方法初始化bean,首先会先执行一些 Aware的注入

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

image.png初期化プロセスは次のとおりimage.png postProcessBeforeInitializationです。初期化メソッドが呼び出される前にメソッドが実行されるため、ユーザー不断的包装对象はnullを返すと、ループを終了できます。オブジェクトがimage.png返さ、初期化メソッドが実行されます。InitializingBeanメソッドは次のとおりです。ここでトリガーされます。初期化メソッドがimage.png実行されpostProcessBeforeInitialization、springは別のライフサイクルメソッドを呼び出します。これにより、ユーザーは複数のレイヤーをラップすることもできます。

Beanプロセスフローチャートを作成する

image.png

image.png

image.png

image.png

おすすめ

転載: juejin.im/post/7086658014777704455