SpringBoot2启动流程源码分析(一) - 入口类

1、SpringBoot启动入口类

入口类的要求是最顶层包下面第一个含有main方法的类,使用注解@SpringBootApplication来启用Spring Boot特性,使用SpringApplication.run()方法来启动Spring Boot项目。

@SpringBootApplication
public class DemoApplication {

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

}

2、进入run方法

  • 参数primarySources:加载的主要资源类即启动类资源。
  • 参数args:传递给应用的应用参数。

主要资源类来实例化一个SpringApplication对象,再调用这个对象的run方法,所以我们分两步来分析这个启动源码。

/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified source using default settings.
 * @param primarySource the primary source to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Class primarySource, String... args) {
	return run(new Class[] { primarySource }, args);
}

/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified sources using default settings and user supplied arguments.
 * @param primarySources the primary sources to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}
  • 初始化SpringApplication对象

1、资源初始化资源加载器为null;

2、断言主要加载资源类不能为null,否则返回不能为空提示报错;

3、初始化主要加载资源类集合并去重;

4、推断当前web应用类型

5、设置应用上下文初始化

6、设置监听器

7、推断主入口应用类

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #SpringApplication(ResourceLoader, Class...)
 * @see #setSources(Set)
 */
public SpringApplication(Class... primarySources) {
	this(null, primarySources);
}

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
	// resourceLoader加载配置资源但是没在这初始化
    this.resourceLoader = resourceLoader;
    // 默认是启动类,不过有可能你自定义了一个配置类放到main class运行就需要配置
	Assert.notNull(primarySources, "PrimarySources must not be null");
    // SpringApplication配置类
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 设置servlet环境
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 获取ApplicationContextInitializer,也是在这里开始首次嘉爱spring.factories文件
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 获取监听器,这里是第二次加载spring.factories文件
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}
  • 执行run方法
/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
    // 1、获取并启动监听器:org.springframework.boot.context.event.EventPublishingRunListener
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 2、构造容器环境,加载application配置文件或者自定义配置文件位置
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        // 3、设置需要忽略的bean
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
        // 4、创建容器
		context = createApplicationContext();
        // 5、实例化SpringBootExceptionReporter.class,用来支持报告关于的错误
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
        // 6、准备容器
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 7、刷新容器
		refreshContext(context);
        // 8、刷新容器后的扩展接口
		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;
}

你可能感兴趣的:(SpringCloud,html)