Spring source code reading (1): resource loading and common life cycle functions

Overview

Let's first look at the general architecture diagram of springimage.png

basic interface

Resource+ResourceLoader

The configuration files we write in the form of xml or annotations are all Resourceresources in spring, and spring also provides one ResourceLoaderto load the resources we write

BeanFactory

Let's first take a look at the inheritance relationship image.pngof beanfactory. The interface of beanFactory defines some basic methods for obtaining beans, nothing special. image.pngNext look at the three interfaces below the bean

  1. HierarchicalBeanFactory

Just define the parent-child relationship of beanFactory image.png2. The interface defined in the official documentation of ListableBeanFactory image.pngis designed to allow people to traverse the beans in the container better, so we can also see that the newly added interface returns an array of bean names

DefaultListableBeanFactory

After looking at the sub-interface of BeanFactory above, let's look at an implementation class. Let's first look at the GenericApplicationContextclass . This class is the parent class of our commonly used IOC container. image.pngWe can see that there is a member variable in this class.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);
复制代码

This class is from spring 信息中心,包含所有bean的定义信息, but the ioc container he uses with us is not an inheritance relationship but a combination relationship

BeanDefinition

BeanDefinition describes an instance of a bean, which can obtain properties such as the bean name, scope, whether it is lazy loaded, and so on.

BeanDefinitionRegistry

A BeanDefinition registry, which contains the mapping relationship of 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.pngThe initialization process is as follows image.png postProcessBeforeInitialization: The method is executed before the initialization method is called, so that the user can 不断的包装对象, if one returns null, then the loop is ended. After the object is image.pngreturned , the initialization method is executed. InitializingBeanThe method is triggered here. After the initialization method is image.pngexecuted postProcessBeforeInitialization, spring will call Another lifecycle method that also allows users to wrap several layers

Create bean process flow chart

image.png

image.png

image.png

image.png

Guess you like

Origin juejin.im/post/7086658014777704455