從Springboot源碼分析啓動過程

從Springboot源碼分析啓動過程

這篇博客主要是通過Springboot的源碼,分析Springboot項目的啓動過程,深入理解spring的工作原理。其次,我對部分源碼加上了註解,新手可以稍微看一下,同時我也希望大佬們能指出我理解有誤的地方。

一、springboot啓動源碼解析

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();//項目計時器開始計時
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();//異常處理類集合
	configureHeadlessProperty();//設置System全局參數
	SpringApplicationRunListeners listeners = getRunListeners(args);//SpringApplicationRunListener.class創建監視器實例
	listeners.starting();//發起starting事件(event)
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);//將啓動參數轉換成spring能解析的格式,例如:--foo=bar --foo="tom"
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();//根據webApplicationType的類型創建Context對象實例
		exceptionReporters = getSpringFactoriesInstances(
				SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);//準備項目運行的環境,加載xml文件中配置的bean
		refreshContext(context);//更新Context 執行用戶定義的postProcessBeanFactory操作,註冊listener相關的bean,初始化所以剩下的單例類
		afterRefresh(context, applicationArguments);//用戶自定義的操作
		stopWatch.stop();//項目計時器結束計時
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);//打印日誌信息
		}
		listeners.started(context);//發起ApplicationStartedEvent事件
		callRunners(context, applicationArguments);//啓動SpringApplication
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);//發起ApplicationReadyEvent事件
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

二、SpringApplication 類部分源碼解析

/**
 * 準備項目運行時的環境變量
 * @param listeners 各種監聽器
 * @param applicationArguments 參數對象
 * @return
 */
private ConfigurableEnvironment prepareEnvironment(
		SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();//初始化environment的Properties和configuration
	configureEnvironment(environment, applicationArguments.getSourceArgs());//添加或替換commandLineArgs在environment中的屬性值 確保profile被正確配置
	listeners.environmentPrepared(environment);//發起ApplicationEnvironmentPreparedEvent事件
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader())
				.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

/**
 * 根據項目類型選擇具體的環境參數類
 * @return
 */
private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
	switch (this.webApplicationType) {
	case SERVLET:
		return StandardServletEnvironment.class;
	case REACTIVE:
		return StandardReactiveWebEnvironment.class;
	default:
		return StandardEnvironment.class;
	}
}

/**
 * 初始化項目上下文環境,具體的初始化內容看參數命名就清楚了
 * @param context
 * @param environment
 * @param listeners
 * @param applicationArguments
 * @param printedBanner
 */
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
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	// 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);
}

/**
 * 從spring的資源目錄下加載factory對象的路徑名,資源文件是META-INF/spring.factories
 * @param type
 * @param parameterTypes
 * @param args
 * @param <T>
 * @return
 */
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
		Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(
			SpringFactoriesLoader.loadFactoryNames(type, classLoader));//從spring的資源目錄下加載factory對象的路徑名,資源文件是META-INF/spring.factories
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
			classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

/**
 * 創建spring各種工廠對象實例 使用classLoader動態加載
 * @param type
 * @param parameterTypes
 * @param classLoader
 * @param args
 * @param names
 * @param <T>
 * @return
 */
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
		Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
		Set<String> names) {
	List<T> instances = new ArrayList<>(names.size());
	for (String name : names) {
		try {
			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
			Assert.isAssignable(type, instanceClass);
			Constructor<?> constructor = instanceClass
					.getDeclaredConstructor(parameterTypes);//使用Constructor反射類調用有參構造函數創建實例
			T instance = (T) BeanUtils.instantiateClass(constructor, args);
			instances.add(instance);
		}
		catch (Throwable ex) {
			throw new IllegalArgumentException(
					"Cannot instantiate " + type + " : " + name, ex);
		}
	}
	return instances;
}

private ConfigurableEnvironment getOrCreateEnvironment() { //配置項目的環境屬性,Note:在java自帶的servlet context初始化之前
	if (this.environment != null) {
		return this.environment;
	}
	switch (this.webApplicationType) {
	case SERVLET:
		return new StandardServletEnvironment();
	case REACTIVE:
		return new StandardReactiveWebEnvironment();
	default:
		return new StandardEnvironment();
	}
}

protected void configureEnvironment(ConfigurableEnvironment environment,
		String[] args) {
	if (this.addConversionService) {
		ConversionService conversionService = ApplicationConversionService
				.getSharedInstance();
		environment.setConversionService(
				(ConfigurableConversionService) conversionService);
	}
	configurePropertySources(environment, args);//添加或替換commandLineArgs在environment中的屬性值
	configureProfiles(environment, args);//確保profile被正確配置
}

protected void load(ApplicationContext context, Object[] sources) {
	if (logger.isDebugEnabled()) {
		logger.debug(
				"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
	}
	BeanDefinitionLoader loader = createBeanDefinitionLoader(
			getBeanDefinitionRegistry(context), sources);//創建一個bean加載器,每個被加載的bean會被自動註冊到cache中
	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();
}

以後我會根據啓動過程和你們一起慢慢的解析spring的各種相關的源碼,有機會的話實現一個@EnableXXXX註解,已經實現但是有bug

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章