Spring Boot源码解析.0.overview

工作如何繁忙,生活如何糟心,至少求知的这一刻是我的…

前言

基于Spring Boot 2.3.1。

从入口开始拆轮

拆轮子可以从它的入口方法开始拆起,先通读再细致地看。Spring Boot的入口已经是老生常谈了:

@SpringBootApplication
public class DemoApplicationMain {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplicationMain.class, args);
    }
}

从SpringApplication#run方法进去,看它做了什么:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

先看看SpringApplication(primarySources)的实现,该方法的实现实际调用了其重载方法。

public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	// 推测web应用环境
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// 加载Spring自身的初始化工厂方法
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// 加载应用监听器
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	// 获取启动main方法的所在类
	this.mainApplicationClass = deduceMainApplicationClass();
}

可以看到,SpringApplication的构造器做了以下操作,通读即可,如需深入了解可自行查看源码,多打断点:

  • 推测web应用环境:通过反射获取classpath中的web应用环境,没有ClassNotFound,从而推测出是否为web应用;
  • 加载Spring自身的初始化工厂方法:读取spring-boot工程的spring.factories资源文件,从中获取到ApplicationContextInitalizer.class的各个实现类;
  • 加载应用监听器:同上读取,从中获取到ApplicationListener.class的各个实现类;
  • 获取启动main方法的所在类:通过主动抛出异常,遍历其异常栈直到异常栈的方法名为main,获取此时的类名。

接着看run方法做了什么:

public ConfigurableApplicationContext run(String... args) {
    // stopWatch,Spring实现的任务监控,在引入Spring的工程中需要监控某些方法运行时间可以用它,没必要自己实现了。
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	// Spring Boot启动错误回调报告器。
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	// 配置java.awt.headless属性为true,如果当前运行设备缺失显示器、键鼠等外设,又需要相应外设的运算能力,那么需要配置该属性为true。
	// 比如服务器基本没有显示器,如果需要输出终端日志信息,那么就要开启它。
	configureHeadlessProperty();
	// 读取spring.factories,获取SpringApplicationRunListener.class的实现类,并一一实例化,目前仅一个实现类。
	// 即EventPublishingRunListener,用于处理Spring刷新上下文之前的事件,见下边的刷新上下文refreshContext(context);。
	// 这里可以打开思路,可以在Spring Boot真正启动前,通过发布一些事件,来做一些前处理。
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
	    // 缓存入参并提供对入参的一定解析能力。
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		// 准备环境,包括web环境、解析入参、确认生效的profiles。
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		// 确认入参中是否配置了spring.beaninfo.ignore, 默认不配置。详见参考文献[1]。
		configureIgnoreBeanInfo(environment);
		/**
		 * 打印Banner,一般打印以下默认Banner。
		 *  .   ____          _            __ _ _
		 * /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
		 * ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
		 * \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
		 *  '  |____| .__|_| |_|_| |_\__, | / / / /
		 *  =========|_|==============|___/=/_/_/_/
		 * :: Spring Boot ::        (v2.3.1.RELEASE)
		**/
		Banner printedBanner = printBanner(environment);
		// 创建应用上下文,如包含web应用上下文,那么此时会通过反射创建;如果没有包含web应用上下文,那么就创建默认的上下文。
		context = createApplicationContext();
		// 读取spring.factories中的配置,获取SpringBootExceptionReporter.class的实现类
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 准备上下文
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// 刷新Spring上下文
		refreshContext(context);// 无实现,有需要可继承SpringApplication.class覆盖该方法。
		afterRefresh(context, applicationArguments);
		// 停止监控,输出如:
		// c.l.blog.NuvoleBiancheApplicationMain    : Started DemoApplicationMain in 13.35 seconds (JVM running for 26.514)
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		// 向所有监听器发布ApplicationStartedEvent。
		listeners.started(context);
		// 将ApplicationRunner和CommandLineRunner一一运行起来。
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
	    // 向exceptionReporters报告异常
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
	    // 向所有监听器发布ApplicationReadyEvent。
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

解析prepareContext见这篇;
解析refreshContext见这篇。

参考文献

[1] https://docs.spring.io/spring-framework/docs/4.2.0.RELEASE/javadoc-api/org/springframework/beans/CachedIntrospectionResults.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园建设方案旨在通过先进的信息技术,为师生提供一个全面智能的感知环境和综合信息服务平台。该方案正处在从信息化第二阶段向第三阶段过渡的关键时期,致力于实现校园服务和管理的全面智能化。 方案的核心目标是构建一个集成的校园地理信息服务平台,通过该平台实现资产管理、房产信息管理、基础设施管理、绿化管理和能源监测管理等功能。同时,该平台将提供校园漫游、信息服务、指引服务、活动通知、用房服务和客流统计等多样化服务,以促进校园的和谐、绿色、平安和便捷。 在技术层面,智慧校园建设方案强调系统集成能力、数据统一分析能力、系统资源共享能力以及大数据集成处理能力。通过这些能力,可以构建统一的校园地理信息平台,提供综合的应用支撑和管理能力,实现系统平滑演进。 应用方向上,智慧校园建设方案围绕和谐校园、绿色校园、平安校园和掌上校园四个维度展开。和谐校园侧重于提供校园漫游、信息服务、指引服务等,增强师生的校园体验。绿色校园则关注资产管理和能源监测,推动校园的可持续发展。平安校园通过视频监控、数字巡更等手段,确保校园安全。掌上校园则利用移动设备,实现校园服务的随时随地访问。 最终,智慧校园建设方案将通过三维虚拟校史馆、720度成像技术等创新应用,提供身临其境的校园漫游体验,同时通过可视化管理和数据分析,优化校园资源配置和运营效率,实现校园管理的智能化和现代化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值