spring源码(一)容器初始化流程

图片

前言

平时在项目开发中,框架啥的都是已经配置好的,开发都是直接上手就开始用了,也不知道是从哪个地方开始的,也不知道原理是什么,出了问题就是百度加谷歌了。 框架极大的增加了我们开发的速率,也方便了开发的上手,但是不知道框架背后的原理,一旦出问题就只能干着急了。 还记得很早之前,就是项目中运用spring自带的异步任务,但是自己并不知道其中的原理,当时代码都是网上复制的,虽然实现了基本功能, 但是后边慢慢的发展着,那个功能出现了很大的问题,但是自己却不知道如何去解决,最后只能百度,谷歌到处找解决问题的办法, 虽然问题解决了,但是却不知道其中的原因是啥,最后自己就去把spring异步任务,线程池的源码都看了一遍, 从此面对这一块的东西,自己已经可以做到从容面对了,不再像之前那样畏手畏脚,都不知道出现问题的具体的原因是啥。 说了这么多,就是想表达:知其然,知其所以然。

正文

这是spring源码阅读的第一篇文章。其实spring源码的入口有很多。

新建一个空的maven项目,然后在pom文件导入:

1
2
3
4
5
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.8.RELEASE</version>
            </dependency>

spring入口方式

自己创建的demo使用了两种方式来创建spring容器:

  1. 使用xml文件配置的形式
1
2
        ApplicationContext context=new ClassPathXmlApplicationContext("spring/quickstart-byname.xml");
        Red bean = context.getBean(Red.class);
  1. 使用Java的config形式
    1
    2
    3
    4
    5
    6
         ApplicationContext context=new AnnotationConfigApplicationContext(SpringScanConfig.class);
         Blue bean = context.getBean(Blue.class);
    
         @Configuration
         @ComponentScan("com.test.spring")
         public class SpringScanConfig {}
    

AnnotationConfigApplicationContext入口

下面我就用第二种方式作为spring源码的入口,还得指定一个配置文件,为了自动注入,配置文件加上了@ComponentScan("com.test.spring")这段代码, 目的是为了让spring去自动发现与注入,不用手动注册bean,当然,也可以在配置文件中手动注册bean信息。 来看看AnnotationConfigApplicationContext的类继承图:

继承图

根据继承图,来看看他们分别干了什么;

  1. AnnotationConfigApplicationContext: 无参构造方法分别给reader和scanner赋值
  2. GenericApplicationContext: 给beanFactory属性赋值
  3. AbstractApplicationContext: 给resourcePatternResolver属性赋值
  4. DefaultResourceLoader: 给classLoader属性赋值

下面看看用部分源码:

1
2
3
4
5
6
7
8
9
10

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        // 构造方法
		this();
        // 注册类信息
		register(componentClasses);
        // 刷新  重点
		refresh();
	}

AbstractApplicationContext.refresh();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
            // 为刷新准备上下文
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            // 告诉子类刷新内部bean工厂,获取bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
            // 准备bean工厂
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                // 准备beanFactory完成后的后置处理
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
                // 执行beanFactory后置处理(所有的bean信息将在这个地方注册进beanFactory中)
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 注册bean后置处理
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
                // 初始化MessageSource
				initMessageSource();

				// Initialize event multicaster for this context.
                // 初始化事件控制器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
                // 初始化其他特别的bean信息
				onRefresh();

				// Check for listener beans and register them.
                // 注册监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
                // 初始化所有非懒加载的bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
                // 完成容器创建
				finishRefresh();
			}
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
                // 清除缓存
				resetCommonCaches();
			}
		}
	}

这就是一个spring容器创建的大概流程,一个spring容器的创建还是挺复杂的,涉及到了方方面面。 后面的笔记在来对其中的一些流程进行详细的分析。

坚持原创技术分享,您的支持将鼓励我继续创作!