1、spring源码解析之概况流程

概要

​ 以前总是很忙,没有时间写博客,现在挤出时间写一些总结性及实用性的博客。

​ 首先聊一下,之所以开始看源码,是因为随着自身对java的理解不断加深,感觉自己对技术架构方面很感兴趣。所以想深入了解一下开源框架的本质,看各种开源框架、jdk源码有一段时间了,也在源码上写了很多自己理解的注释,一直没有整体总结,偶尔想起来有一些思路,但是容易忘记,所以想做一些总结,每一个我觉得非常复杂的核心流程,我都会用一张或时许图、流程图来进行学习总结。

​ 总的来说,spring的总体流程不是很复杂,但是细思极恐;每一个类、每一个方法的内部实现能牵扯出很多与之相关联的类;其中实现错综复杂,不过不管怎么难,带着设计模式的思想、以及多思考,多实践,多总结的角度,多看几遍,终归会有所收获(可以自己手绘一些uml时序图、流程图来加深理解)。

​ 本文及后续文章主要基于spring 5.0源码分析spring 核心的 ioc和aop,首先缕清spring运行的整体脉络流程。由于注解驱动(无xml)的流行,本文不会涉及xml的上下文及容器刷新流程(注意:作者之前有使用过ssm,涉及过xml配置,个人觉得xml配置会让人思想上更容易理解spring容器、bean的定义等等,感觉现在直接使用spring boot的人可能渐渐忽略了spring才是基石)。

1.程序入口:加载配置类

​ 本文主要采用AnnotationConfigApplicationContext 作为程序的起点。

public class MyApplication {
	public static void main(String[] args) {
		//spring上下文,启动一个spring应用程序。
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyApp.class);
		Car bean =(Car) context.getBean("car");
		System.out.println(bean.getColor()+bean.getPrice());
	}
}

2.注解配置上下文AnnotationConfigApplicationContext

AnnotationConfigApplicationContext:注解配置上下文。

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		//this()由于继承关系,所以会先调用父类的构造方法,在调用子类的构造方法
		/**
		 * @Author coyhzx
		 * @Description 类继承结构(暂不涉及接口)DefaultResourceLoader -> AbstractApplicationContext ->GenericApplicationContext -> AnnotationConfigApplicationContext
		 *   {@link DefaultResourceLoader} 初始化当前线程的classLoader
		 *   {@link AbstractApplicationContext} 初始化资源模式匹配解析器 PathMatchingResourcePatternResolver
		 *   {@link GenericApplicationContext}  初始化 ioc底层容器 DefaultListableBeanFactory
		 *   {@link AnnotationConfigApplicationContext}  初始化 reader 注解的bean的读取器,scanner 类路径的bean的扫描器
		 **/
		this();
		//componentClasses 注册单个组件bean
		register(componentClasses);
		//刷新容器
		refresh();
	} 


AnnotationConfigApplicationContext的无参构造this();

	public AnnotationConfigApplicationContext() {
		//创建一个注解的bean的读取器,猜想一下,很关键,要想读取注解,是不是要注册一些内置的BeanPostProcess后置处理器来处理注解bean。
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//创建一个类路径的bean的扫描器
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

3.刷新上下文

refresh()刷新容器

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 刷新上下文前的准备
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 获取beanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// beanFactory的一些准备工作
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 留给子类Context去实现,目前为空
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 调用 beanFactoryPostProcessors beanFactory的后置处理器
				//重点: 解析入口的配置类
				invokeBeanFactoryPostProcessors(beanFactory);

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

				// Initialize message source for this context.
				//初始化消息源
				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();
			}
		}
	}

​ 简单来说:整体流程其实已经走完了,感觉有点走马观花,但是其中每一个方法每一个new对象,每一个父子继承的实现其实很复杂。得慢慢梳理。先看一下AnnotationConfigApplicationContext得类图,从图中可以看成,spirng把一个上下文的接口抽象出来了很多顶级接口,和抽象类和实现类,看多了很多源码,摸清楚了一些spring框架的一些小特点,通常spring接口会有顶级接口,定义规范,抽象类实现接口的公用方法,具体的特性交给不同实现类去实现,这里着重介绍一些核心得关键接口和类。

4.核心类AnnotationConfigApplicationContext的类图结构

在这里插入图片描述

BeanFactory: Bean工厂的顶级接口。里面定义了变量factorbean的前缀&,getBean()、getType()、是否单例、是否原型的方法等等。

ResourceLoader: 资源加载的顶级接口。很简单,里面仅仅定义了classpath的url,getClassLoader()、getResource(String location)方法。
DefaultResourceLoader:默认的资源加载类。加载classpath下的资源文件。

AbstractApplicationContext:抽象的上下文类。实现了可配置的上下文接口ConfigurableApplicationContext,是一个很重要的类,refresh()刷新容器的主要逻辑就在其中。

GenericApplicationContext:广泛普通的上下文类。我们真正底层的ioc容器,bean工厂DefaultListableBeanFactory就是在它的初始化中创建的。

AnnotationConfigApplicationContex:注解配置的上下文类。很关键,是可以直接定位加载注解配置类的上下文。

BeanDefinitionRegistry:bean的注册接口。定义了注册bean、移除bean等接口。

5.跟踪源码进入ioc

​ 先简单的介绍AnnotationConfigApplicationContext#register(componentClasses)方法,以及跟踪源码,可以直接进入我们常说的ioc容器之中,看着上下文是如何帮我们在上下文中创建一个BeanDefinition,并放入容器中。

​ 好了,尽管我省略了很多细节,但是整体的配置类BeanDefinition注册流程通过下图展示,spring在ioc容器中注册了bean的定义了,那么如何去完成实例化bean的实例呢,请期待我下一篇文章把!
在这里插入图片描述
下一篇:2、spring源码解析之单例bean的实例化

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值