从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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SpringBoot2的启动流程是通过@SpringBootApplication注解自动化配置来实现的。该注解包含了多个注解的组合,其中包括@ComponentScan、@EnableAutoConfiguration和@Configuration等。通过这些注解,Spring Boot会自动扫描并加载配置类,并根据自动配置规则来配置应用程序。 具体而言,当应用程序启动时,Spring Boot会创建一个Spring应用程序上下文。在创建上下文的过程中,会先加载主配置类(通常是包含main方法的类),然后根据@ComponentScan注解扫描指定包下的所有组件。 接下来,Spring Boot会根据@EnableAutoConfiguration注解自动配置应用程序。这个注解会根据classpath和条件匹配的规则,加载配置类,并将它们注册到应用程序上下文中。这些配置类使用了@Configuration注解,会声明一些Bean,并根据条件来决定是否生效。 最后,Spring Boot会启动应用程序,并执行相应的事件处理器。这些事件处理器可以通过自定义ApplicationListener来实现。在应用程序运行期间,Spring Boot会触发不同的事件,并调用相应的事件处理器。 参考文献: 引用:SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析(三) [2] 引用:SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六) 引用:该系列主要还是Spring的核心源码,不过目前Springboot大行其道,所以就从Springboot开始分析。最新版本是Springboot2.0.4,Spring5,所以新特性本系列后面也会着重分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tomshidi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值