Spring IOC 容器预启动流程源码探析

在应用程序中,一般是通过创建ClassPathXmlApplicationContextAnnotationConfigApplicationContext这两个最底层子类来启动Spring IOC容器:

  • ClassPathXmlApplicationContext: xml文件配置版
  • AnnotationConfigApplicationContext: 注解版

由于当下越来越流行基于Java注解的配置来创建我们的Bean,所以本文主要以注解版进行探析。

AnnotationConfigApplicationContext的类关系结构

我们先来看看我们探讨的起点

public class Main {

	public static void main(String[] args) {
new AnnotationConfigApplicationContext(Config.class);
}
@Configuration
public static class Config{ }
}

demo简简单单,那么,这里发生了什么?或许,我们可以先看看AnnotationConfigApplicationContext的类关系结构:

我们可以看到AnnotationConfigApplicationContext最上面有两个顶级接口:

  • BeanFactory: Spring的核心接口,纯粹的bean容器,主要定义了与Bean的相关方法
  • ResourceLoader:资源加载器,定义了getResource方法

继承自三个父类:

  • DefaultResourceLoader: 默认的资源加载器,实现了三种加载资源的方式

    1. 通过path加载资源

    2. 通过classpath加载资源

    3. 通过URL加载资源

  • AbstractApplicationContext: 实现了ApplicationContext接口的抽象类,主要功能

    1. 实现了启动IOC容器的核心方法:refresh()

    2. 发布事件

    3. 大量getBean相关的操作, 主要通过抽象方法getBeanFactory基于子类实现

    4. 大量留于子类扩展的空方法

    5. 消息国际化

  • GenericApplicationContext:

    1. 使用组合的方式引进了最底层的BeanFactory实现类:DefaultListableBeanFactory

    2. 定义了registerBean的相关操作,其实是通过DefaultListableBeanFactory实现的

不难发现,ApplicationContext名副其实,确实就是一个应用上下文,对于bean的相关操作,容器的管理,依旧是由我们的BeanFactory进行实现。

准备启动

1. 创建我们的实例:AnnotationConfigApplicationContext

new AnnotationConfigApplicationContext(Config.class);

2.进入到AnnotationConfigApplicationContext构造方法

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}

3. 调用我们的空构造方法,这里要先实例化我们的父类

3.1 实例化DefaultResourceLoader

public DefaultResourceLoader() {
this.classLoader = ClassUtils.getDefaultClassLoader();
}

ClassUtils.getDefaultClassLoader()主要有两步操作

//获取线程上下文的类加载器
ClassLoader cl = = Thread.currentThread().getContextClassLoader();
if(cl == null) //为空则获取系统的类加载器 即为应用类加载器
cl = ClassLoader.getSystemClassLoader();

这里我们非Tomcat环境,所以返回的是AppClassLoader

3.2 实例化AbstractApplicationContext

//为BeanFactoryPostProcessor赋初始值
List<BeanFactoryPostProcessor> BeanFactoryPostProcessor = new ArrayList<>();
public AbstractApplicationContext() {
//引入一个资源解析器
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}

3.3 实例化GenericApplicationContext

public GenericApplicationContext() {
//引入BeanFactory实现
this.beanFactory = new DefaultListableBeanFactory();
}

3.4 实例化自己

public AnnotationConfigApplicationContext() {
//初始化基于注解的bean定义扫描器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化基于classpath的bean定义扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
3.4.1 AnnotatedBeanDefinitionReader初始化过程
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
//registry就是我们AnnotationConfigApplicationContext
this.registry = registry;
//引入条件表达式计算器 处理@Conditional注解
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//注册所有与注解相关的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}

registerAnnotationConfigProcessors(registry, null)中主要做了以下几件事情:

  • DefaultListableBeanFactory赋值了两个引用

    //依赖排序器,用于处理添加了Priority、Order注解以及实现了Ordered接口的bean
    beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    //@Autowire候选解析器
    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  • 往容器中注册了6个后置处理器的bean定义

    注册配置类的后置处理器

    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    def.setSource(source);
    registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);

    注册处理@Autowired注解的后置处理器

    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME);

    注册处理@Required注解的后置处理器(5.1版本开始已被废弃)

    RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME);

    注册处理JSR-250规范注解的后置处理器,@Resource,@PostConstruct,@PreDestroy

    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    def.setSource(source);
    registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME);

    注册处理@EventListener注解的后置处理器

    RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    def.setSource(source);
    registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME);

    注册事件监听工厂,给上面的EventListenerMethodProcessors使用

    RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    def.setSource(source);
    registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME);
3.4.2 ClassPathBeanDefinitionScanner初始化过程

经历了一系列的构造器传递

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
} public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
} public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}

最终实现的构造器方法

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//默认为true
if (useDefaultFilters) {
//注册默认的过滤器
registerDefaultFilters();
}
//设置环境
setEnvironment(environment);
//设置资源加载器
setResourceLoader(resourceLoader);
}

registerDefaultFilters方法

protected void registerDefaultFilters() {
//加入扫描@Component注解的过滤器,这样就能扫到@Controller,@Service...
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//JSR-250规范的注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
}
catch (ClassNotFoundException ex) {
}
try {
//JSR-330规范的注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
}
catch (ClassNotFoundException ex) {
}
}

4. 构造方法执行完毕,执行register(annotatedClasses)方法,将配置类的bean定义注册到容器中

public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
//这里就使用了刚刚初始化的AnnotatedBeanDefinitionReader扫码器
//annotatedClasses即为在入口处传进的自定义配置类Config.class
this.reader.register(annotatedClasses);
}
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
//这里我们只传了一个,只有一次循环
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
//spring的特点,真正实现的都是do开头的方法
doRegisterBean(annotatedClass, null, null, null);
}
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//将class封装到bean定义中
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//由于配置类并未使用@Conditional注解,直接返回false
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
} abd.setInstanceSupplier(instanceSupplier);
//解析bean定义的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//处理普通的bean定义注解,@Lazy @Primary @DependsOn @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
} BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//根据scopeMetadata中的proxy-mode属性判断是否需要进行代理封装,默认否
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//将bean定义注册到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

前期准备工作已基本完毕,可以开始调用refresh方法启动IOC容器了。

准备花个30天时间,系统的来整理一下我对spring源码的认识:

Spring 源码系列
  1. Spring源码分析之 IOC 容器预启动流程(已完结)
  2. Spring源码分析之BeanFactory体系结构(已完结)
  3. Spring源码分析之BeanFactoryPostProcessor调用过程(已完结)
  4. Spring源码分析之Bean的创建过程
  5. Spring源码分析之什么是循环依赖及解决方案
  6. Spring源码分析之AOP从解析到调用
  7. Spring源码分析之事务管理(上),事物管理是spring作为容器的一个特点,总结一下他的基本实现与原理吧
  8. Spring源码分析之事务管理(下) ,关于他的底层事物隔离与事物传播原理,重点分析一下
Spring Mvc 源码系列
  1. SpringMvc体系结构
  2. SpringMvc源码分析之Handler解析过程
  3. SpringMvc源码分析之请求链过程
Mybatis 源码系列

暂定


追更,可关注我的公众号:奇客时间,分享纯粹为了乐趣,也有一种成就感吧,笔者这篇文章先就到这

Spring IOC 容器预启动流程源码探析的更多相关文章

  1. SpringBoot 源码解析 (二)----- Spring Boot精髓:启动流程源码分析

    本文从源代码的角度来看看Spring Boot的启动过程到底是怎么样的,为何以往纷繁复杂的配置到如今可以这么简便. 入口类 @SpringBootApplication public class He ...

  2. Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段

    目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...

  3. Spring IOC容器启动流程源码解析(一)——容器概念详解及源码初探

    目录 1. 前言 1.1 IOC容器到底是什么 1.2 BeanFactory和ApplicationContext的联系以及区别 1.3 解读IOC容器启动流程的意义 1.4 如何有效的阅读源码 2 ...

  4. Spark(四十九):Spark On YARN启动流程源码分析(一)

    引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...

  5. 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码

    Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...

  6. Android Activity启动流程源码全解析(1)

    前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...

  7. Android Activity启动流程源码全解析(2)

    接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...

  8. Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)

    上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...

  9. SpringBoot启动流程源码分析

    前言 SpringBoot项目的启动流程是很多面试官面试中高级Java程序员喜欢问的问题.这个问题的答案涉及到了SpringBoot工程中的源码,也许我们之前看过别的大牛写过的有关SpringBoot ...

随机推荐

  1. Mybatis联合查询(一)

    Mybatis的简单联合查询操作: 实体类: Employee: package com.test.mybatis; public class Employee { private Integer i ...

  2. Oracle 回滚段undo

    Undo的作用 数据的回滚 一致性读 表的闪回(事务,查询的闪回..) 失败会话的恢复 回滚rollback操作 SQL> archive log list; ORA-01031: 权限不足 S ...

  3. 哈希,hash

    Hash,一般翻译做散列.杂凑,或音译为哈希.----摘自百度百科 先来看个题:给你一坨一些键值集<key,value>,\(key\)的范围是\([1,10^{10}]\),每次询问\( ...

  4. 在react项目添加看板娘(react-live2d)

    有留意到看板娘这么个东西,简直就是我们程序员+动漫迷的挚爱.但是回观网上,大多只是在老旧的html的静态引入.vue甚至也有几个不怎么维护的,还是老旧的不行的SDK2.X的版本.这这这这!我们的rea ...

  5. 跟我一起学.NetCore之中间件(Middleware)应用和自定义

    前言 Asp.NetCore中的请求管道是通过一系列的中间件组成的,使得请求会根据需求进行对应的过滤和加工处理.在平时开发中会时常引用别人定义好的中间件,只需简单进行app.Usexxx就能完成中间件 ...

  6. Oracle序列Sequence用法

    序列 序列(Sequence)是用来生成连续的整数数据的对象.序列常常用来作为主键中增长列,序列中的可以升序生成,也可以降序生成.创建序列的语法是:语法结构:创建序列 CREATE SEQUENCE ...

  7. ansible中定义变量的若干方法

    Ansible支持十几种定义变量的方式 根据优先级排序的定义方式: Inventory变量 Host Facts变量 Playbook变量 Playbook提示变量 变量文件 命令行变量 1.Inve ...

  8. 1000000 / 60S 的 RocketMQ 不停机,扩容,平滑升级!

    一.背景 1.各业务系统持续迭代过程中,JDK.SpringBoot.RocketMQ Client 等框架也进行了升级,高版本的 RocketMQ Client 发送的消息到低版本中,在控制台中午无 ...

  9. 【Java并发编程】从CPU缓存模型到JMM来理解volatile关键字

    目录 并发编程三大特性 原子性 可见性 有序性 CPU缓存模型是什么 高速缓存为何出现? 缓存一致性问题 如何解决缓存不一致 JMM内存模型是什么 JMM的规定 Java对三大特性的保证 原子性 可见 ...

  10. 一文带你熟悉JAVA IO这个看似很高冷的菇凉

    Java IO 是一个庞大的知识体系,很多人学着学着就会学懵了,包括我在内也是如此,所以本文将会从 Java 的 BIO 开始,一步一步深入学习,引出 JDK1.4 之后出现的 NIO 技术,对比 N ...