温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java SpringBoot核心源码的示例分析

发布时间:2021-12-29 10:21:18 来源:亿速云 阅读:99 作者:柒染 栏目:开发技术

本篇文章给大家分享的是有关Java SpringBoot核心源码的示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

    SpringBoot源码主线分析

    我们要分析一个框架的源码不可能通过一篇文章就搞定的,本文我们就来分析下SpringBoot源码中的主线流程。先掌握SpringBoot项目启动的核心操作,然后我们再深入每一个具体的实现细节,注:本系列源码都以SpringBoot2.2.5.RELEASE版本来讲解

    1.SpringBoot启动的入口

    当我们启动一个SpringBoot项目的时候,入口程序就是main方法,而在main方法中就执行了一个run方法。

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

    2.run方法

    然后我们进入run()方法中看。代码比较简单

    	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    		// 调用重载的run方法,将传递的Class对象封装为了一个数组
    		return run(new Class<?>[] { primarySource }, args);
    	}

    调用了重载的一个run()方法,将我们传递进来的类对象封装为了一个数组,仅此而已。我们再进入run()方法。

    	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    		// 创建了一个SpringApplication对象,并调用其run方法
    		// 1.先看下构造方法中的逻辑
    		// 2.然后再看run方法的逻辑
    		return new SpringApplication(primarySources).run(args);
    	}

    在该方法中创建了一个SpringApplication对象。同时调用了SpringApplication对象的run方法。这里的逻辑有分支,先看下SpringApplication的构造方法中的逻辑

    3.SpringApplication构造器

    我们进入SpringApplication的构造方法,看的核心代码为

    	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    		// 传递的resourceLoader为null
    		this.resourceLoader = resourceLoader;
    		Assert.notNull(primarySources, "PrimarySources must not be null");
    		// 记录主方法的配置类名称
    		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    		// 记录当前项目的类型
    		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    		// 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化
    		// 并将加载的数据存储在了 initializers 成员变量中。
    		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    		// 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
    		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    		// 反推main方法所在的Class对象 并记录在了mainApplicationClass对象中
    		this.mainApplicationClass = deduceMainApplicationClass();
    	}

    在本方法中完成了几个核心操作

    1.推断当前项目的类型

    2.加载配置在spring.factories文件中的ApplicationContextInitializer中的类型并实例化后存储在了initializers中。

    3.和2的步骤差不多,完成监听器的初始化操作,并将实例化的监听器对象存储在了listeners成员变量中

    4.通过StackTrace反推main方法所在的Class对象

    上面的核心操作具体的实现细节我们在后面的详细文章会给大家剖析

    4.run方法

    接下来我们在回到SpringApplication.run()方法中。

    	public ConfigurableApplicationContext run(String... args) {
    		// 创建一个任务执行观察器
    		StopWatch stopWatch = new StopWatch();
    		// 开始执行记录执行时间
    		stopWatch.start();
    		// 声明 ConfigurableApplicationContext 对象
    		ConfigurableApplicationContext context = null;
    		// 声明集合容器用来存储 SpringBootExceptionReporter 启动错误的回调接口
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    		// 设置了一个名为java.awt.headless的系统属性
    		// 其实是想设置该应用程序,即使没有检测到显示器,也允许其启动.
    		//对于服务器来说,是不需要显示器的,所以要这样设置.
    		configureHeadlessProperty();
    		// 获取 SpringApplicationRunListener 加载的是 EventPublishingRunListener
    		// 获取启动时到监听器
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		// 触发启动事件
    		listeners.starting();
    		try {
    			// 构造一个应用程序的参数持有类
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    			// 创建并配置环境
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    			// 配置需要忽略的BeanInfo信息
    			configureIgnoreBeanInfo(environment);
    			// 输出的Banner信息
    			Banner printedBanner = printBanner(environment);
    			// 创建应用上下文对象
    			context = createApplicationContext();
    			// 加载配置的启动异常处理器
    			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    					new Class[] { ConfigurableApplicationContext.class }, context);
    			// 刷新前操作
    			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    			// 刷新应用上下文 完成Spring容器的初始化
    			refreshContext(context);
    			// 刷新后操作
    			afterRefresh(context, applicationArguments);
    			// 结束记录启动时间
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
    			// 事件广播 启动完成了
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
    			// 事件广播启动出错了
    			handleRunFailure(context, ex, exceptionReporters, listeners);
    			throw new IllegalStateException(ex);
    		}
    		try {
    			// 监听器运行中
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, null);
    			throw new IllegalStateException(ex);
    		}
    		// 返回上下文对象--> Spring容器对象
    		return context;
    	}

    在这个方法中完成了SpringBoot项目启动的很多核心的操作,我们来总结下上面的步骤

    • 创建了一个任务执行的观察器,统计启动的时间

    • 声明ConfigurableApplicationContext对象

    • 声明集合容器来存储SpringBootExceptionReporter即启动错误的回调接口

    • 设置java.awt.headless的系统属性

    • 获取我们之间初始化的监听器(EventPublishingRunListener),并触发starting事件

    • 创建ApplicationArguments这是一个应用程序的参数持有类

    • 创建ConfigurableEnvironment这时一个配置环境的对象

    • 配置需要忽略的BeanInfo信息

    • 配置Banner信息对象

    • 创建对象的上下文对象

    • 加载配置的启动异常的回调异常处理器

    • 刷新应用上下文,本质就是完成Spring容器的初始化操作

    • 启动结束记录启动耗时

    • 完成对应的事件广播

    • 返回应用上下文对象。

    以上就是Java SpringBoot核心源码的示例分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI