Spring-IOC容器启动流程

130 阅读6分钟

前言

对于Java开发者来说,使用最多的框架必然是spring了,而对于spring,我们常常都会说spring就是一个bean容器,帮我们管理bean;而这个容器的上层接口就是beanFactory;

BeanFactory定义了许多对bean的操作方法,比如通过名称获取bean,判断是否单例bean等

这一节来介绍下IOC容器的底层是啥样子的,以及简单梳理下spring启动流程

大纲

通过本文你将学到:

  • spring常用的一些概念以及类,包括用途及关系
  • Spring容器的启动流程源码

常用类及概念

因为IOC容器工厂相关的子类太多,我们先梳理下有哪些,具体的作用是什么,然后再方便介绍源码

BeanFactory基础容器

image.png ListableBeanFactory: 表示这些 Bean 是可列表化的(会有多个bean),可以通过这个获取bean配置清单

HierarchicalBeanFactory: 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean

AutowireCapableBeanFactory: 定义 Bean 的自动装配规则(提供创建bean,自动注入,初始化以及应用bean的后处理器)

DefaultListableBeanFactory 这是最终实现类(综合上述所有功能,主要是对bean注册后的处理)

上面是BeanFactory的一些实现类,BeanFactory可以认为是一个基础的容器接口,定义了一些简单的对bean的操作(获取对象、实例化对象等);下面介绍spring中更高级的容器ApplicationContext。

BeanFactory实操XmlBeanFactory(已过时)
BeanFactory的实现是懒加载的,即在使用时加载
public class HelloWorldApp { 
   public static void main(String[] args) { 
      XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource("beans.xml")); 
      HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");    
      obj.getMessage();    
   }
}

他们之间的区别可以在网上看看别的文章:

BeanFactory vs ApplicationContext

ApplicationContext高级容器

ApplicationContext继承于BeanFactory,即实现了BeanFactory的所有功能,还有更多其他的功能 MessageSource:支持信息源,可以实现国际化

ResourcePatternResolver:访问资源,如URL和文件

ApplicationEventPublisher:支持应用事件,消息发送、响应机制

常用实现类:GenericApplicationContext,ClasspathXmlApplicationContext

DefaultSingletonBeanRegistry

这是单例bean注册器,实现了SingletonBeanRegistry;提供bean的获取、注册等功能;大名鼎鼎的三级缓存(SingletonFactories,earlySingletonObjects,singletonObjects)也是在这里面

DefaultSingletonBeanRegistry是spring的核心类

BeanDefinition

对于BeanDefinition,其实大家都很熟悉,就是bean的定义;在spring中,我们在xml中的配置,都是先转成beandefinition(存储在比如DefaultListableBeanFactory的hashmap中);然后再实例化成bean对象的(DefaultSingletonBeanRegistry中)

完成解析任务的类就是我们的BeanDefinitionReader

www.jianshu.com/p/55b8ef2eb…

BeanFactoryPostProcessor & BeanPostProcessor

BeanFactoryPostProcessor经常用来修改bean定义,或者添加bean定义

定义:BeanFactoryPostProcessor的主体是BeanFactory,并且该接口中只定义了一个方法,其将会在ApplicationContext内部的BeanFactory加载完bean的定义后,但是在对应的bean实例化之前进行回调

核心方法:postProcessBeforeInitialization、postProcessAfterInitialization

BeanFactoryPostProcessor经常用来针对bean进行proxy

定义:BeanPostProcessor 该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的

核心方法:postProcessBeanFactory

BeanFactoryPostProcessor还有个子接口BeanDefinitionRegistryPostProcessor,里面提供了postProcessBeanDefinitionRegistry方法,这个把BeanDefinitionRegistry暴露给我我们,可以用来注册beanDefinition等

spring容器启动流程

接下来,开始下重头戏-分析下spring容器的源码;根据前面介绍的,spring高级容器一定是ApplicationContext的一个子类,常用的有xml(ClassPathXmlApplicationContext),注解(AnnotationConfigApplicationContext),这里用AnnotationConfigApplicationContext来作为例子:

测试代码:

public class SpringIocContext {
    public static void main(String[] args) {
//        ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");
        AnnotationConfigApplicationContext annotationConfigApplicationContext = 
                new AnnotationConfigApplicationContext(Test.class);
    }
}

构造方法

	/**
	 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
	 * from the given component classes and automatically refreshing the context.
	 * @param componentClasses one or more component classes — for example,
	 * {@link Configuration @Configuration} classes
	 */
	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 调用空构造方法
		this();
        // 将配置类的BeanDefinition注册到容器中
		register(componentClasses);
        // 调用refresh()方法刷新容器
		refresh();
	}

可以发现构造方法里面主要做了三件事:

  • 初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
  • 将配置类的BeanDefinition注册到容器中
  • 调用refresh()方法刷新容器

接下来,一步步分析这三件事。。

初始化Spring容器

构造方法初始化spring容器时主要做了三件事:

  • 实例化beanFactory工厂(DefaultListableBeanFactory):这个在父类GenericApplicationContext中
  • 实例化注解配置读取器BeanDefinitionReader(AnnotatedBeanDefinitionReader)
  • 实例化路径扫描器ClassPathBeanDefinitionScanner,用于对指定的包目录进行扫描查找 bean 对象

对于第二步中,重点介绍下:org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors

这个方法主要是注册一些内置的组件到容器中,比如:

  • ConfigurationClassPostProcessor: beanFactory 后置处理器,用来完成 bean 的扫描与注入工作;实现了BeanFactoryPostProcessor
  • AutowiredAnnotationBeanPostProcessor: bean 后置处理器,用来完成 @AutoWired 自动注入,实现了BeanPostProcessor
  • CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory等其他组件

注册SpringConfig配置类到容器中

这块主要是将我们前面调用容器构造方法时传入的bean解析成一个 BeanDefinition 然后注册到容器;核心逻辑在:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean

逻辑无非就是反射解析注解+对象,然后注册到容器;具体代码不多说

refresh()容器刷新流程

efresh刷新容器就是整体spring容器启动的核心流程,其中主要做的事有如下几个:

prepareRefresh

刷新前的预处理

obtainFreshBeanFactory();

获取 beanFactory,即前面创建的【DefaultListableBeanFactory】

1.刷新beanFactory并设置序列化id

2.返回前面创建的BeanFactory

prepareBeanFactory

预处理 beanFactory,向容器中添加一些组件,代码具体对于以下:

  • 设置 bean 表达式解析器
  • 添加一个 BeanPostProcessor【ApplicationContextAwareProcessor】
  • 设置某些bean不能通过自动装配注入(即不能使用注解直接使用)
  • 设置注册某些bean可以通过自动装配注入
  • 添加一个 BeanPostProcessor【ApplicationListenerDetector】
  • 添加编译时的 AspectJ
  • 注册 environment 组件、systemProperties 组件、systemEnvironment 组件

postProcessBeanFactory

子类通过重写这个方法可以在 BeanFactory 创建并与准备完成以后做进一步的设置

invokeBeanFactoryPostProcessors

执行 BeanFactoryPostProcessor 方法,beanFactory 后置处理器;

这一段代码很多,但整体逻辑就是执行postProcessBeanDefinitionRegistry()方法、postProcessBeanFactory() 方法;并且按照PriorityOrdered、Ordered的顺序去执行

registerBeanPostProcessors

向容器中注入BeanPostProcessor;(仅仅注入而非使用),在后续spring创建、初始化bean时会用到,包括代理、自动注入、循环依赖等

initApplicationEventMulticaster

初始化事件派发器,在注册监听器时会用到(用来承载监听器)

主要是往beanFactory注册一个事件派发器(ApplicationEventMulticaster),默认是SimpleApplicationEventMulticaster,有自定义就用自定义的

registerListeners

扫描ApplicationListener,并将其添加到派发器中ApplicationEventMulticaster;

主要是将之前步骤初始化的,和容器中所有自定义的加入派发器中

finishBeanFactoryInitialization

实例化所有非懒加载的bean,具体逻辑在这个方法中;比较复杂,后续单独讲解

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons


finishRefresh

容器初始化完成后,后续的扫尾工作;

包括清理缓存,初始化生命周期处理器,发布容器刷新事件等。

后续

后续详细介绍下springBean的生命周期