Leitura do código-fonte do Spring (1): carregamento de recursos e funções comuns do ciclo de vida

Visão geral

Vamos primeiro olhar para o diagrama de arquitetura geral da primaveraimagem.png

interface básica

Resource+ResourceLoader

Os arquivos de configuração que escrevemos na forma de xml ou anotações são todos Resourcerecursos na visualização do spring, e o spring também fornece um ResourceLoaderpara carregar os recursos que escrevemos

BeanFactory

Vamos primeiro dar uma olhada no relacionamento de herança imagem.pngdo beanfactory.A interface do beanFactory define alguns métodos básicos para obter beans, nada de especial.A imagem.pngseguir ver as três interfaces abaixo do bean

  1. HierarchicalBeanFactory

Apenas defina o relacionamento pai-filho do beanFactory imagem.png2. A interface definida na documentação oficial do ListableBeanFactory imagem.pngfoi projetada para permitir que as pessoas percorram melhor os beans no contêiner, então também podemos ver que a interface recém-adicionada retorna um array de nomes de bean

DefaultListableBeanFactory

Depois de olhar para a subinterface de BeanFactory acima, vamos olhar para uma classe de implementação. Vamos primeiro olhar para a GenericApplicationContextclasse . Essa classe é a classe pai do nosso contêiner IOC comumente usado. imagem.pngPodemos ver que há uma variável de membro nesta classe .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);
复制代码

Esta classe é do spring 信息中心,包含所有bean的定义信息, mas o container ioc que ele usa conosco não é um relacionamento de herança e sim um relacionamento de combinação

BeanDefinition

BeanDefinition descreve uma instância de um bean, que pode obter propriedades como o nome do bean, escopo, se ele é carregado lentamente e assim por diante.

BeanDefinitionRegistro

Um registro BeanDefinition, que contém o relacionamento de mapeamento de BeanDefinition

ApplicationContext

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

Aware

imagem.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方法

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

创建单实例Bean流程

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

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

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

Bean属性赋值过程

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

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

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

spring的后置处理器

spring提供了三种后置处理器

  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. InitializingBean

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

BeanFactoryPostProcessor

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

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

imagem.png

工厂后置增强的实际用途

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

BeanPostProcessor 注册

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

InstantiationAwareBeanPostProcessor

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

SmartInstantiationAwareBeanPostProcessor

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

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

InstantiationAwareBeanPostProcessor

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

MergedBeanDefinitionPostProcessor

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

PopulateBean

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

PropertyValues

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

BeanPostProcessor

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

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

imagem.pngO processo de inicialização é o seguinte imagem.png postProcessBeforeInitialization: O método é executado antes que o método de inicialização seja chamado, para que o usuário possa 不断的包装对象, se retornar null, o loop é encerrado. Após o imagem.pngretorno , o método de inicialização é executado. InitializingBeanO método é acionado aqui. Depois que o método de inicialização for imagem.pngexecutado postProcessBeforeInitialization, o spring chamará Outro método de ciclo de vida que também permite que os usuários envolvam várias camadas

Criar fluxograma de processo de bean

imagem.png

imagem.png

imagem.png

imagem.png

Acho que você gosta

Origin juejin.im/post/7086658014777704455
Recomendado
Clasificación