深入SpringBoot源码(一)从SpringApplication的构造方法入门源码

前言

本文涉及代码所使用的SpringBoot版本为2.6.3(这是截至此文发布时Spring Cloud Alibaba最新版本适配的SpringBoot版本,点击此处可查看Spring Cloud Alibaba与SpringBoot的版本适配情况),如果未来版本的SpringBoot源码有较大变动,不建议再学习本文。

学习SpringBoot源码的入口点

@SpringBootApplication
public class TestMain {
   

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

}

上面这段代码相信使用SpringBoot的大家再熟悉不过了,是SpringBoot的应用程序启动入口,这也是SpringApplication(org.springframework.boot.SpringApplication)的最主要作用。SpringApplication.run方法是本系列文章讲解源码的入口点,接下来我们就来一层一层深挖SpringApplication.run背后到底做了什么能让我们的SpringBoot应用正常启动并提供服务。

我们先来看一下SpringApplication的类层次性结构。(这是IDEA的类层次性结构视图,默认快捷键Ctrl+H)
在这里插入图片描述

可以看到SpringApplication没有继承除Object以外的任何类也没有实现任何接口,不需要考虑复杂的类层次性关系,这也是其适合作为学习SpringBoot源码入口点的主要原因。

SpringApplication的构造方法

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

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

上面就是SpringApplication的run方法源码(run方法到底做了什么以及run方法返回的ConfigurableApplicationContext是什么会在以后文章中详解,因为要理解这些需要依赖后面讲的源码。本文的关注点在SpringApplication的构造方法),可以看到最终的run方法调用了构造方法new 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));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

构造方法SpringApplication(Class<?>... primarySources)最终调用SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources)。下面来看SpringApplication构造方法每步代码的作用。

初识ResourceLoader、Resource

SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources)(由于传入的是ResourceLoader是null,在构造函数中并看不出具体作用,所以本文先初步了解接口方法,后面的文章会讲解ResourceLoader的实现类源码)在这里插入图片描述
ResourceLoader(org.springframework.core.io.ResourceLoader)是用于加载资源(例如,类路径或文件系统资源)的策略接口。

public interface ResourceLoader {
   

	/** 从类路径加载的伪 URL 前缀:“classpath:” */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;


	/**
	 * 返回指定资源位置的Resource句柄。
	 */
	Resource getResource(String location);

	/**
	 * 返回此ResourceLoader使用的ClassLoader 。
	 */
	@Nullable
	ClassLoader getClassLoader();

}

ResourceLoader的层次性关系(子类型):
在这里插入图片描述

Resource(org.springframework.core.io.Resource) 是从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口。

public interface Resource extends InputStreamSource {
   

	/**
	 * 确定此资源是否实际以物理形式存在
	 */
	boolean exists();

	/**
	 * 指示是否可以通过getInputStream()读取此资源的非空内容
	 */
	default boolean isReadable() {
   
		return exists();
	}

	/**
	 * 指示此资源是否表示具有打开流的句柄。
	 */
	default boolean isOpen() {
   
		return false;
	}

	/**
	 * 确定此资源是否代表文件系统中的文件。
	 */
	default boolean isFile() {
   
		return false;
	}

	/**
	 * 返回此资源的 URL 句柄。
	 */
	URL getURL() throws IOException;

	/**
	 * 返回此资源的 URI 句柄。
	 */
	URI getURI() throws IOException;

	/**
	 * 返回此资源的文件句柄。
	 */
	File getFile() throws IOException;

	/**
	 * 返回一个ReadableByteChannel 。
	 */
	default ReadableByteChannel readableChannel() throws IOException {
   
		return Channels.newChannel(getInputStream());
	}

	/**
	 * 确定此资源的内容长度。
	 */
	long contentLength() throws IOException;

	/**
	 * 确定此资源的最后修改时间戳。
	 */
	long lastModified() throws IOException;

	/**
	 * 创建与此资源相关的资源。
	 */
	Resource createRelative(String relativePath) throws IOException;

	/**
	 * 确定此资源的文件名,即通常是路径的最后部分:例如,“myfile.txt”。
	 * 如果这种类型的资源没有文件名,则返回null 。
	 */
	@Nullable
	String getFilename();

	/**
	 * 返回此资源的描述,用于在使用资源时输出错误。
	 */
	String getDescription();

}

Resource的层次性关系(父类型):

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值