SpringBoot启动过程run()方法中的prepareContext()方法解析

196 阅读4分钟

prepareContext()方法解析

prepareContext,顾名思义就是准备上下文,这里内部执行了上下文的初始化器、通知SpringApplicationRunListener监听器到了各个阶段、设置beanFactory属性、解析主类(中间有一些特殊的配置类也能被加载,但是水比较浅,还没看到,就提一嘴)信息注册进BeanDefinition。主要还是在补充上下文的信息。

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		// 1.设置环境变量和上下文(这里准确的说,应该是补充上下文)
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		// 2.遍历SpringApplication中搜集的initializers集合,依次执行initialize方法
		// GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);
		// 上面的方法用于获取类的泛型类型
		applyInitializers(context);
		// 3.通知运行时的listeners,执行到了prepared阶段了
		listeners.contextPrepared(context);
		// 4.关闭bootstrapContext上下文
		// 内部最后是调用ApplicationListener#onApplicationEvent()通知监听器
		bootstrapContext.close(context);
		// 5.启动日志
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 6.注册args和banner到bean容器
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		// 7.设置beanFactory属性
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
			((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
			if (beanFactory instanceof DefaultListableBeanFactory) {
				((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
			}
		}
		// 8.设置BeanFactory的后置处理器
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
		// 9.Load the sources
		// 获取程序的入口,一般是获取@SpringBootApplication注解修饰的含main方法的类,以及配置类或者@Configuration修饰的类
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 10.把source集合下的类,解析成BeanDefinition,默认情况下这步只会注册我们的启动类
		load(context, sources.toArray(new Object[0]));
		// 11.通知监听器,执行到context-loaded步骤了
		listeners.contextLoaded(context);
	}

applyInitializers()方法

applyInitializers() 方法,主要是执行在创建SpringApplication()方法时,加载ApplicationContextInitializer.class的实现类中的初始化方法

// SpringApplication类的构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		// 这里加载了ApplicationContextInitializer.class的实现类
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
// applyInitializers方法中调用它们的initialize(方法)
protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			// 这些initialize有做初始化的,有给context对象set值的
			initializer.initialize(context);
		}
	}

getAllSources()方法

这里说一下getAllSources()方法,内部有两个重要属性this.primarySources和this.sources,都是SpringApplication中的属性

public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		// 启动时加载默认为空
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

在Spring框架中,primarySources和sources是SpringApplication类中的两个属性,它们用于存储应用程序的入口类。这两个属性的类型都是Set<Class<?>>,即存储的是类的引用。

  • primarySources属性用于存储应用程序的主入口类。在Spring Boot应用程序中,通常会有一个或多个主入口类,这些类使用@SpringBootApplication注解,并包含main方法。这些主入口类会被Spring Boot框架自动扫描和加载。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// 创建SpringApplication时,会把你的主类,添加到primarySources
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
  • sources属性用于存储应用程序的其他入口类。这些类可以是任何配置类,也可以是任何包含@Configuration注解的类。这些类会被Spring Boot框架加载,但不会作为主入口类。

load()方法

这里简单说一下load方法,这里会将主类组装成BeanDefinition,放入BeanDefinitionRegistry。

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
       logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    // getBeanDefinitionRegistry()方法内部很简单,直接把context进行了强转
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
       loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
       loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
       loader.setEnvironment(this.environment);
    }
    loader.load();
}
// 获取BeanDefinitionRegistry直接强转,说明我们传入的上下文,其实就包含了BeanDefinitionRegistry的实现
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
		if (context instanceof BeanDefinitionRegistry) {
			return (BeanDefinitionRegistry) context;
		}
		if (context instanceof AbstractApplicationContext) {
			return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
		}
		throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
	}
// 创建BeanDefinitionLoader,其实就是一个赋值操作
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
		Assert.notNull(registry, "Registry must not be null");
		Assert.notEmpty(sources, "Sources must not be empty");
		this.sources = sources;
		this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
		this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
		this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
		this.scanner = new ClassPathBeanDefinitionScanner(registry);
		this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
	}

load内部最后会执行到doRegisterBean()方法,最终是把BeanDefinition注册到beanDefinitionMap属性中

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {
      //创建一个注解类型的通用BeanDefinition
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		//判断有没有condition条件,根据条件判断是否需要装载
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
      //下面一大段都是给BeanDefinition内部的属性赋值
		abd.setInstanceSupplier(supplier);
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		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));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}
           // 把BeanDefinition信息和beanName放入BeanDefinitionHolder
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		// 根据代理模式生成对应的definitionHolder
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// 注册beanDefinition到DefaultListableBeanFactory中的beanDefinitionMap属性中
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

结论

prepareContext()方法内部其实还是对ConfigurableApplicationContext的补充,以及一些初始化操作。实际做的,还是Springboot加载META-INF/spring.factories中的实现类,要提前放入ConfigurableApplicationContext上下文中,为后续Spring去执行refresh方法创建bean做准备。

  • 给ConfigurableApplicationContext赋值环境变量
  • 给ConfigurableApplicationContext内部的属性赋值
  • 把ConfigurableApplicationContext传给初始化类,执行内部的初始化方法
  • 注册一些后置处理器到ConfigurableApplicationContext
  • 解析启动类信息,包装成BeanDefinition
  • 通知监听器,到了Springboot启动到了prepare和context-loaded步骤了