springboot源码剖析(一) 总体启动流程
前言
之前阅读STL(C++)源码的时候,有所感悟: 大佬的代码总会实践到部分设计模式、新型语法特性,亦或是精巧的算法和数据结构。
读源码的技巧:大局入手,之后细细品味,重点地方做到逐行阅读。
故学习源码也是提升自己认知和能力的一种途径,本篇章主要介绍springboot源码相关。
链接:
概念
Spring Boot是一个基于Spring的套件,它帮我们预组装了Spring的一系列组件,以便以尽可能少的代码和配置来开发基于Spring的Java应用程序。
源码剖析
源码剖析不可避免要贴大量代码,逐行贴上注释解释流程,重要的接口我会放在后面解释。
总体启动流程
1. 构造
// springApplication.class 构造 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 初始化部分属性 ... // 主类设置为入口传参的类 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // web应用类型SERVLET this.webApplicationType = WebApplicationType.deduceFromClasspath(); // ★ 加载初始化器类和监听器类 // 扫描类路径下META-INFO/spring.factories中的org.springframework.context.ApplicationContextInitializer this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 扫描类路径下META-INFO/spring.factories中的org.springframework.context.ApplicationListener this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // 推导main函数的入口类 this.mainApplicationClass = this.deduceMainApplicationClass(); }
2. 启动
// springApplication.class 启动 public ConfigurableApplicationContext run(String... args) { // 秒表类,创建计时器 StopWatch stopWatch = new StopWatch(); // 计时开始 stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); // 配置headless模式,表示运行在服务器器端,在没有显示器器和鼠标键盘的模式下工作,模拟输入输出设备功能 this.configureHeadlessProperty(); // 扫描META-INF/spring-factories 中的org.springframework.boot.SpringApplicationRunListener,并初始化广播器 SpringApplicationRunListeners listeners = this.getRunListeners(args); // ★ 发布ApplicationStartingEvent事件 listeners.starting(); Collection exceptionReporters; try { // 解析命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // ★ 准备环境配置 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); // 增加系统配置参数spring.beaninfo.ignore this.configureIgnoreBeanInfo(environment); // 打印springboot图案 Banner printedBanner = this.printBanner(environment); // 根据推导的应用类型, 创建一个AnnotationConfigServletWebServerApplicationContext的实例化对象,实际就是spring容器的子类实现 context = this.createApplicationContext(); // 异常报告类,处理异常用 exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); // 上下文准备 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // ★ 上下文刷新 this.refreshContext(context); // 空操作 this.afterRefresh(context, applicationArguments); // 计时结束 stopWatch.stop(); // 打印启动耗时 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } // 发布ApplicationStartedEvent事件 listeners.started(context); // 执行脚本 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { // 发布ApplicationReadyEvent事件 listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
本文重点是getSpringFactoriesInstances方法,用来查找并获取某个工厂实例
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader();
// 1. classLoader搜索META-INF/spring.factories里匹配的类 Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 2. 通过反射实例化这些类 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }