spring boot 加载过程分析(三)

826 阅读4分钟

接着上一篇,现在主要来看一下prepareContext方法的内容,先看代码:

prepareContext执行过程

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
	// 设置环境配置
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	// 初始化实现类调用
	applyInitializers(context);
	// 事件传播
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}

	// Add boot specific singleton beans
	context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
	}

	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

postProcessApplicationContext()

如果在初始化SpringApplication时有指定beanName生成器与资源加载器,这里会把其注册到beanFactory上;但我们这里都没有指定,所以该方法什么也不做。

applyInitializers()

我们在初始化SpringApplication时,通过getSpringFactoriesInstances方法查找classpath下的ApplicationContextInitializer的实现类应该还有印象吧。这里其实就是回调该接口的实现,并传入参数context。

protected void applyInitializers(ConfigurableApplicationContext context) {
	for (ApplicationContextInitializer initializer : getInitializers()) {
	    Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
			initializer.getClass(),ApplicationContextInitializer.class);
	    // 回调
	    initializer.initialize(context);
	}
}

接着就是把该阶段(context准备)的事件广播,然后把之前初始化的参数对象及banner打印注册到容器上。然后看一下load方法

load()

这里我不再贴代码,简单介绍一下该方法做了哪些。 首先,我们知道source数组这里其实只有一个元素,就是我们的启动类。load方法先创建了一个BeanDefinitionLoader类,其初始化过程有点类似之前分析的applicationcontext,也是指定了reader, scanner解析类等。比如这里指定了AnnotatedBeanDefinitionReader来解析带有@Component注解的类。因为这里的source是我们的启动类,所以实际就把@SpringBootApplication的类解析成beanDefinition注册到容器上。ok,知道它干了什么就行。但这里既然提到了AnnotatedBeanDefinitionReader类,那我们就详细了解一下它是具体内容。

AnnotatedBeanDefinitionReader

之前的内容中,已介绍过其初始化的过程,里面有两个成员变量beanNameGenerator,scopeMetadataResolver来作beanName生成,scope解读的。下面看一下它的核心方法registerBean

public void registerBean(Class<?> annotatedClass) {
    doRegisterBean(annotatedClass, null, null, null);
}

调用doRegisterBean方法,如下

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
                // 设置回调
		abd.setInstanceSupplier(instanceSupplier);
		//解析scope
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		// 生成beanName
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
                //注解属性处理 @Lazy, @Primary, @DependsOn
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		// 处理传入的注解属性
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		//自定义扩展实现回调
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}
                // 包装definition
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		// 根据scope注册不同的代理模式beanDefinition
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// 注册
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

上面的方法相对比较简单,AnnotatedGenericBeanDefinition是beanDefinition的一个扩展实现,增加了收集注解的元数据信息。而关于代理模式的使用,这里不再详述。到这里,我们基本了解了一个被@Component注解的bean是怎么被解析beanDefinition,那下面再看一下是怎么注册到beanFactory的。

registerBeanDefinition

通过方法名可以猜到,它出自BeanDefinitionRegistry接口;跟踪该方法的实现,发现它到了DefaultListableBeanFactory这里,该类之前初始化过程已分析过,知道它维护了一个map类型的成员变量beanDefinitionMap。下面看一下注册代码:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
                // 主要是方法注入的校验
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;
                // 从map中查询是否已存在注册bean
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		// 如果已存在,各种日志输出...
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			// 覆盖
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
		        // 检查factory的bean创建解析过程是否已开始,是则需要同步
			if (hasBeanCreationStarted()) {
				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;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
		        // 如果bean被覆盖或者已实例化,重置一下
			resetBeanDefinition(beanName);
		}
	}

从代码可以看到,注册beanDefinition其实就是将其放入map中以待后续解析实例化。这里注意当解析实例化工作已启动时需要同步处理。对已存在的beanDefinition或者bean实例则重置。bean的实例化后面碰到再详细分析,这里不再详述。

到这里,我们分析了context的创建与准备,但基本都是spring的一些环境配置,资源加载器,beanDefinition解析器设置等相关的准备功能,即使加载注册部分beanDefinition也是内置处理器或启动类,真正解析我们自己写的类则还没开始解析,包括bean生命周期等。那么接下来的refreshContext方法则就是做这些工作的,下篇我们着重来跟踪分析一下代码。