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. 【Gin-API系列】部署和监控(九)

    本文是[Gin-API系列]的最后一篇文章,简单介绍如何在生产环境的部署架构和监控手段. 生产部署 部署架构 使用Nginx加Keepalived的方式搭建,可以达到高可用的效果,并可以横向扩容 如何 ...

  2. Agumaster 将爬虫取股票名称代号子系统分出来成agumaster_crawler, 两系统通过RabbitMq连接

    agumaster_crawler系统负责启动爬虫取得数据,之后便往队列中推送. agumaster_crawler系统中pom.xml关于RabbitMq的依赖是: <!-- RabbitMq ...

  3. 网易云uwp

    起因 昨天晚上折腾Ubuntu 莫名其妙任务栏的网易云音乐图标消失了,今早才发现原来是更新了. but,这个更新真的是让人一言难尽 upw更新一下直接变成了桌面版? 折腾 重新装回老版uwp 网易云U ...

  4. flag在index里

    题目:http://123.206.87.240:8005/post/ 我们来看这一题 首先打开题目 他让点击就点击呗 跳转到另一个新的界面 这就没了??? ... 没思路就对了    //假装证明自 ...

  5. Linux下vim的安装及配置

    目录 一.vim的下载 二.vim的基本知识 三.vim的基本配置 四.vim与外部文件的复制粘贴 一.vim的下载 Ubuntu系统,输入命令: sudo apt install vim Cento ...

  6. 微信小程序爬坑记

    1.this.setData修改数组里的值1).data: { hide:[true,true] },this.setData({ 'hide[0]': false});2).var str = &q ...

  7. pyhton:操作redis

    一.redis介绍 redis是一种非关系型数据库:没有表结构,没有字段,没有sql语句.只是用get获取数据,set插数据,类似字典.比如mangodb,redis redis的数据全存在内存,re ...

  8. 在腾讯云云函数计算上部署.NET Core 3.1

    云厂商(腾讯云.Azure等)提供了Serverless服务,借助于Serverless,开发人员可以更加专注于代码的开发,减少运维的成本.腾讯云的函数计算提供了很多运行库,对.NET的支持需要通过c ...

  9. Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  10. node 进阶 | 通过node中如何捕获异常阐述express的特点

    node如何捕获异常 node基于js的单线程,有了非阻塞异步回调的概念,但是在处理多个并发连接时,并发环境要求高,最重要的是单线程,单核CPU,一个进程crash则web服务都crash,但是为什么 ...