SpringBoot 启动方法run()源码解析

 更新时间:2021年03月25日 08:39:43   作者:码上代码  
这篇文章主要介绍了SpringBoot 启动方法run()源码赏析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

入口

通常一个简单的SpringBoot基础项目我们会有如下代码

@SpringBootApplication
@RestController
@RequestMapping("/")
public class Application {

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

}

值得关注的有SpringApplication.run以及注解@SpringBootApplication

run方法

public ConfigurableApplicationContext run(String... args) {
	 // 秒表
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		// 获取监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 监听器启动
		listeners.starting();
		try {
		 // application 启动参数列表
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 配置忽略的bean信息
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			// 创建应用上下文
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
		 // 准备上下文,装配bean
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 上下文刷新
			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);
		}
		return context;
	}

getRunListeners

获取监听器

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		// 获取 Spring Factory 实例对象
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}


	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		// 读取 spring.factories
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 创建SpringFactory实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		/**
		 * 排序 {@link Ordered}
		 */
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
createSpringFactoriesInstances
 @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对象
 			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
 			Assert.isAssignable(type, instanceClass);
 			// 构造器获取
 			Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
 			// 创建具体实例
 			T instance = (T) BeanUtils.instantiateClass(constructor, args);
 			// 加入实例表中
 			instances.add(instance);
 		}
 		catch (Throwable ex) {
 			throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
 		}
 	}
 	return instances;
 }

printBanner

private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		// 创建打印器
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
		 // 输出
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
 // 输出
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}
	Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
		Banner banner = getBanner(environment);
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}

最终输出内容类:org.springframework.boot.SpringBootBanner

class SpringBootBanner implements Banner {

	private static final String[] BANNER = { "", " . ____  _  __ _ _",
			" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
			" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
			" =========|_|==============|___/=/_/_/_/" };

	private static final String SPRING_BOOT = " :: Spring Boot :: ";

	private static final int STRAP_LINE_SIZE = 42;

	@Override
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
		for (String line : BANNER) {
			printStream.println(line);
		}
		String version = SpringBootVersion.getVersion();
		version = (version != null) ? " (v" + version + ")" : "";
		StringBuilder padding = new StringBuilder();
		while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
			padding.append(" ");
		}

		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
				AnsiStyle.FAINT, version));
		printStream.println();
	}

}

希望通过本篇对于springboot启动方法的解读,让大家对springboot底层有了一个大致了解,只分析了主要方法,希望对大家有帮助

到此这篇关于SpringBoot 启动方法run()源码赏析的文章就介绍到这了,更多相关SpringBoot 启动run()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • idea注解参数换行时间日期格式设置方法

    idea注解参数换行时间日期格式设置方法

    这篇文章主要介绍了idea注解参数换行时间日期格式设置方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • Java编程发展历史(动力节点Java学院整理)

    Java编程发展历史(动力节点Java学院整理)

    Java的历史可以追溯到1991年4月,Sun公司的James Gosling领导的绿色计划(Green Project)开始着力发展一种分布式系统结构,使其能够在各种消费性电子产品上运行,他们使用了C/C++/Oak语言。由于多种原因,绿色计划逐渐陷于停滞状态
    2017-03-03
  • Spring事务管理中关于数据库连接池详解

    Spring事务管理中关于数据库连接池详解

    事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就 回退到事务开始未进行操作的状态。事务管理是Spring框架中最为常用的功能之一,我们在使用Spring Boot开发应用时,大部分情况下也都需要使用事务
    2022-12-12
  • Spring BeanFactory和FactoryBean有哪些区别

    Spring BeanFactory和FactoryBean有哪些区别

    这篇文章主要介绍了Spring BeanFactory 与 FactoryBean 的区别详情,BeanFactory 和 FactoryBean 的区别却是一个很重要的知识点,在本文中将结合源码进行分析讲解,需要的小伙伴可以参考一下
    2023-02-02
  • Java值传递之swap()方法不能交换的解决

    Java值传递之swap()方法不能交换的解决

    这篇文章主要介绍了Java值传递之swap()方法不能交换的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Springboot打包部署修改配置文件的方法

    Springboot打包部署修改配置文件的方法

    这篇文章主要介绍了Springboot打包部署修改配置文件的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

    Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

    这篇文章主要介绍了Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法 的相关资料,需要的朋友可以参考下
    2016-01-01
  • SpringCloud分布式事务Seata部署和集成过程

    SpringCloud分布式事务Seata部署和集成过程

    这篇文章主要介绍了SpringCloud分布式事务Seata部署和集成过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-10-10
  • Spring Boot实现STOMP协议的WebSocket的方法步骤

    Spring Boot实现STOMP协议的WebSocket的方法步骤

    这篇文章主要介绍了Spring Boot实现STOMP协议的WebSocket的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • java重试机制使用RPC必须考虑幂等性原理解析

    java重试机制使用RPC必须考虑幂等性原理解析

    这篇文章主要为大家介绍了java重试机制使用RPC必须考虑幂等性原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论