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

23 篇文章 0 订阅
6 篇文章 0 订阅


前言

基于学习遗忘曲线收敛太快,决定将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)的判断

在这里插入图片描述

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呢?
在这里插入图片描述
这5个类对象的具体作用,我们以后再说。

  1. 此处还得记住AnnotatedBeanDefinitionReader还有个register方法,这个方法的作用是把某个类注册进Spring的容器中,
  2. reader之所以可以进行register操作是因为reader里面拥有一个BeanDefinitionRegistry的属性,而我们默认的DefaultListableBeanFactory又正好实现了这个接口,
  3. 所以利用**this.reader = new AnnotatedBeanDefinitionReader(this);**进行reader的设定的时候,其实就是把DefaultListableBeanFactory对象设置成了reader里面的registry属性。
  4. 可以发现我们的applicationContext和scaner通过BeanFactory对象进行了绑定。
  5. 再看看我们的DefaultListableBeanFactory的register实际逻辑:
@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {

		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			// do something
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

可以看到register具体做的事儿,其实就是往BeanDefinitionMap里面put对应的beanDefinition,如果对应name之前已经存在beanDefinition,就覆盖,同时重新生成对应的bean实例。

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

总结

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值