Spring源码-注解版

作为小白,学习Spring框架用了很久很久,而且还处于只会用的阶段。刚步入公司实习,深刻觉得框架源码的掌握非常重要。公司项目基于源码做了很多拓展,但是我连原生框架都没看明白,深感自己菜的离谱。
今天斗胆尝试写一篇从头到尾的文章。整个流程类似建模,先大致讲完整个执行过程,不清楚或一两句话讲不明白的地方使用红色标记,后面慢慢完善。我深知文章中有很多错误、不详细、讲的不好的地方,欢迎各位指错、私信讨论、写在评论区也可。
选择注解版是因为SpringBoot底层大量用到了注解,此文章也是为SpringBoot做准备。5.3.20版本是随便选择的一个版本。
文章中也会借鉴很多前辈的知识,本文章保证只学习使用。

Spring注解版启动流程

Spring的版本 5.3.20

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.20</version>
        </dependency>

创建主启动类AopTest,创建一个注解版的Spring容器对象。进入AnnotationConfigApplicationContext查看注解容器的创建过程。后面AnnotationConfigApplicationContext对象简称注解容器
Spring源码-注解版_第1张图片
先调用本类的无参构造方法
在这里插入图片描述
第一行代码 this.getApplicationStartup().start(“spring.context.annotated-bean-reader.create”),这里我们看看AnnotationConfigApplicationContext继承树。
Spring源码-注解版_第2张图片
AnnotationConfigApplicationContext继承GenericApplicationContext,GenericApplicationContext继承AbstractApplicationContext。
this.getApplicationStartup()就是获取AbstractApplicationContext类中的成员变量。
这个成员变量在对象创建的时候就赋值了初始值private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;实际上就是创建了一个new DefaultApplicationStartup()对象。
(讲几个重要的,继承的实在太多了,而且很多我也不清楚)
Spring源码-注解版_第3张图片
这个类的start方法可以看到,其实在这个阶段传入的name并没有什么用。只返回了一个内部类对象。end方法也是一个空方法。(所以第一、三步在这里不重要,至于有什么用等我学会了再回来补上。)现在重点看二、四两步。

class DefaultApplicationStartup implements ApplicationStartup {

	private static final DefaultStartupStep DEFAULT_STARTUP_STEP = new DefaultStartupStep();

	@Override
	public DefaultStartupStep start(String name) {
		return DEFAULT_STARTUP_STEP;
	}

	static class DefaultStartupStep implements StartupStep {

		private final DefaultTags TAGS = new DefaultTags();

		@Override
		public void end() {

		}
        //删掉了一些不重要的方法减少篇幅
}

AnnotationConfigApplicationContext类中只用两个属性reader和scanner。见名知意。一个注解的bean定义信息读取器和一个类路径下bean定义信息扫描器。都传入了this对象。
this.reader = new AnnotatedBeanDefinitionReader(this);进入这个方法看看。
调用另一个构造方法,再进入另一个构造方法之前先通过this对象获取一个环境对象。这个环境对象在Spring容器中起了至关重要的作用。我们先看如何获取环境对象。
在这里插入图片描述
我们正在创建的这个AnnotationConfigApplicationContext对象继承了EnvironmentCapable接口,所以直接返回对象中的环境对象。那么我们的这个环境对象属性在哪个类中呢。
Spring源码-注解版_第4张图片
其实就在AbstractApplicationContext对象中。提供了private ConfigurableEnvironment environment属性和get、set方法。当然,在创建的时候并没有赋值默认值。这个时候环境对象是空的。在get方法中继续调用了同类中的createEnvironment方法。实际上就是创建一个标准环境对象并返回。
Spring源码-注解版_第5张图片
Spring源码-注解版_第6张图片
环境对象有了,进入构造方法之前我们先看看AnnotatedBeanDefinitionReader有哪些成员变量
registry:就是我们正要创建的容器对象。
beanNameGenerator:bean的名字生成对象,向容器中添加bean时,没指定名称通过这个类自动生成名称。
scopeMetadataResolver:解析bean的作用域(scope)的,原生类型(prototype)还是单态(singleton)。
ConditionEvaluator:条件解析器,解析@Conditional之类的注解信息。
看到这些成员变量,就会觉得存在即合理。AnnotatedBeanDefinitionReader去读取bean的时候需要这些对象参与工作。beanNameGenerator和scopeMetadataResolver赋值了默认值。
Spring源码-注解版_第7张图片
所以,我们再看构造方法就会清晰很多,因为只有registry和conditionEvaluator为空值了,构造方法就是给这两个属性赋值啊。至于最后一行代码。从方法名可以看出,我们需要往注解容器中添加一些注解的处理器。
Spring源码-注解版_第8张图片
进入最后一行方法。
第一行代码就是获取bean工厂对象DefaultListableBeanFactory。注解容器对象继承了GenericApplicationContext对象。DefaultListableBeanFactory对象就是GenericApplicationContext中的成员变量。在GenericApplicationContext对象的构造方法中给这个工厂对象赋值了默认值。所以这里可以获取到一个DefaultListableBeanFactory对象。
Spring源码-注解版_第9张图片
Spring源码-注解版_第10张图片
bean工厂对象创建完之后很多属性都是空的,所以获取到工厂对象之后,给工厂对象设置了Order的排序比较器和自动注入的候选者解析器(这个有什么用以后再说,bean工厂对象创建的时候赋值了一个简单解析器,但这里不符合要求,所以设置新的ContextAnnotation解析器)

再后面,从注解容器中判断是否包含bean定义信息。这里的判断逻辑,就是获取到工厂对象,从工厂对象中的beanDefinitionMap中获取对象.我们这里是刚刚创建的工厂对象,Map集合中当然什么都没有。所以registerPostProcessor方法就是向beanDefinitionMap集合中添加对象。(讲到这里可能类与类之间的关系,作用有点混乱。后续专门写一篇讲环境对象、工厂对象的关系和作用。)
Spring源码-注解版_第11张图片
后面基本类似,就是往容器中添加bean定义信息。先简单介绍下各个bean的作用。(这里讲的很模糊,后期补)
ConfigurationClassPostProcessor:Bean工厂的后置处理器,解析配置类的注解。
AutowiredAnnotationBeanPostProcessor:属性注入的后置处理器@Autowired。
CommonAnnotationBeanPostProcessor:Java注解支持,@Resource。
EventListenerMethodProcessor:将应用中每个使用@EventListener注解定义的事件监听方法变成一个ApplicationListener实例注册到容器。
DefaultEventListenerFactory:创建事件监听器的工厂。
往beanDefinitionMap中添加完这些定义信息后。AnnotatedBeanDefinitionReader构造方法就结束了。后面再看ClassPathBeanDefinitionScanner。

你可能感兴趣的:(Spring注解版源码分析,spring)