欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring源码学习(一):Spring容器创建和初始化工作准备

程序员文章站 2022-05-03 23:38:09
文章目录前言一、Spring是什么?二、探究1. Spring容器启动1.1 容器类型(contextClass)的判断1.2 容器的实例化2. 容器的创建及实例化过程2.1 构造方法读下去2.1.1 scanner的作用2.1.2 reader的作用总结前言基于学习遗忘曲线收敛太快,决定将Spring源码的解读记录下来。今天是第一篇,容器的启动那就开始吧~一、Spring是什么?用java的应该都清楚Spring框架是什么,目前市面上的主流java框架也都会做和Spring的结合。Sprin...


前言

基于学习遗忘曲线收敛太快,决定将Spring源码的解读记录下来。今天是第一篇,容器的启动


那就开始吧~

一、Spring是什么?

用java的应该都清楚Spring框架是什么,目前市面上的主流java框架也都会做和Spring的结合。Spring两大利器:IOC+AOP。API的学习可以借助官网,因为有时候中文翻译或某些同学的博客翻译有问题:https://spring.io/projects/spring-framework#learn

二、探究

鉴于大家现在java项目几乎都是使用Springboot,那我们从Springboot项目的启动切入口查看Spring容器的启动。具体springboot版本就不指定了,Spring容器启动差别不大。

1. Spring容器启动

从Springboot的run方法开始进入

1.1 容器类型(contextClass)的判断

Spring源码学习(一):Spring容器创建和初始化工作准备

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		// 通过反射生成ApplicationContext类型的对象
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

通过判断webApplicationType来进行容器创建类型contextClass的设置。
因为默认的webApplicationType在前期被deduce成了SERVLET,所以创建的是AnnotationConfigServletWebServerApplicationContext

/**
	 * The class name of application context that will be used by default for web
	 * environments.
	 */
	public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

1.2 容器的实例化

这个其实不算难了,一句话总结,就是利用反射就行实例化拿到容器的对象。
具体是BeanUtils.instantiateClass(contextClass)

  1. 拿到Class的构造方法clazz.getDeclaredConstructor()
  2. 获取构造方法的参数类型
  3. 调用ctor.newInstance(argsWithDefaultValues)进行容器对象创建及初始化

2. 容器的创建及实例化过程

2.1 构造方法读下去

构造方法代码如下:

/**
	 * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
	 * to be populated through {@link #register} calls and then manually
	 * {@linkplain #refresh refreshed}.
	 */
	public AnnotationConfigServletWebServerApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

对于java来说,调用自己的无参构造方法之前,会把父类的无参构造方法都调用:
AnnotationConfigServletWebServerApplicationContext ->
ServletWebServerApplicationContext ->
GenericWebApplicationContext ->
GenericApplicationContext->

/**
	 * Create a new GenericApplicationContext.
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}

由此可以看到applicationContext里面的beanFactory属性默认会被初始化为DefaultListableBeanFactory对象。

2.1.1 scanner的作用

scaner的作用,顾名思义,扫描器,就是后期为了扫描所有生成的.class文件,然后根据class文件生成BeanDefinition放入到Spring的容器里,至于BeanDefinition的作用,后面再讲,先记住即可。

2.1.2 reader的作用

那reader的作用呢,其实就是为了补充scaner的力所不能及。怎么说呢,因为scaner扫描出来的class,需要具体的类对象来进行操作,咱们姑且用X来代替,那么X来把别人加入到容器,X从何而来呢?其实对于我们这些程序员来说,可能最直观的想法,就是直接new呗。但是Spring作为一个牛逼开源框架,他的开发者选择了一种尽量自洽的方式来处理,也就是通过reader把这些X类的BeanDefinition放入到了applicationContext里面,然后后续通过调用getBean的方式从容器中拿到X。

具体逻辑可以从AnnotatedBeanDefinitionReader的构造方法debug下去看到,最终会调用:

/**
	 * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
	 * using the given {@link Environment}.
	 * @param registry the {@code BeanFactory} to load bean definitions into,
	 * in the form of a {@code BeanDefinitionRegistry}
	 * @param environment the {@code Environment} to use when evaluating bean definition
	 * profiles.
	 * @since 3.1
	 */
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//在这一步会进行刚刚说的X的BeanDefinition的放入
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

具体放入了哪些类的BeanDefinition呢?
Spring源码学习(一):Spring容器创建和初始化工作准备
这5个类对象的具体作用,我们以后再说。
此处还得记住AnnotatedBeanDefinitionReader还有个register方法,这个方法的作用是把某个类注册进Spring的容器中

而相对于reader初始化做的事儿,scanner对象的初始化就显得很简单,就是做了一些属性的赋值。

总结

以上就是今天要讲的内容,本文仅仅简单介绍了Springboot使用的ApplicationContext的contextClass的选取及对象实例化的一些基本工作。
也就是Springboot的run方法中的**context = createApplicationContext();**进行的逻辑。

本文地址:https://blog.csdn.net/liangsheng_g/article/details/109571193