栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot启动过程:SpringApplication及SpringApplicationBuilder

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot启动过程:SpringApplication及SpringApplicationBuilder

SpringBoot应用的启动是基于SpringApplication类的,下面一步步地分析。

构造方法及初始化

其构造方法有二,都调用了initialize方法,完成注解源的配置。

	public SpringApplication(Object... sources) {
		initialize(sources);
	}
    public SpringApplication(ResourceLoader resourceLoader, Object... sources) {
		this.resourceLoader = resourceLoader;
		initialize(sources);
	}
	private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		this.webEnvironment = deduceWebEnvironment();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
  • initialize方法首先将注解源设置到成员变量this.sources中,然后deduceWebEnvironment方法中根据类路径是否有javax.servlet.Servlet、org.springframework.web.context.ConfigurableWebApplicationContext这两个类判断是否是web环境this.webEnvironment。
  • 利用spring.factories机制机制加载ApplicationContextInitializer和ApplicationListener。
  • 然后找到main方法所在类mainApplicationClass。
run方法

run方法是程序运行的主要方法

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			listeners.finished(context, null);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
  • SpringApplicationRunListeners加载,利用spring.factories机制加载SpringApplicationRunListener,封装到SpringApplicationRunListeners,SpringApplicationRunListener定义了一些容器的生命周期方法,SpringApplicationRunListeners就是为了方便循环调用多个SpringApplicationRunListener的方法。在容器的各个生命周期时刻调用相应的方法。
public interface SpringApplicationRunListener {

	
	void starting();

	
	void environmentPrepared(ConfigurableEnvironment environment);

	
	void contextPrepared(ConfigurableApplicationContext context);

	
	void contextLoaded(ConfigurableApplicationContext context);

	
	void finished(ConfigurableApplicationContext context, Throwable exception);

}

  • 将主方法入参args封装为ApplicationArguments(默认实现DefaultApplicationArguments),方便获取命令行参数
public interface ApplicationArguments {

	
	String[] getSourceArgs();

	
	Set getOptionNames();

	
	boolean containsOption(String name);

	
	List getOptionValues(String name);

	
	List getNonOptionArgs();

}
  • 准备ConfigurableEnvironment,其中configureEnvironment将命令行参数封装为SimpleCommandLinePropertySource添加到环境中,配置profile。
	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}
	protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

	
	protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						name + "-" + args.hashCode(), args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

	
	protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		environment.getActiveProfiles(); // ensure they are initialized
		// But these ones should go first (last wins in a property key clash)
		Set profiles = new LinkedHashSet(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
	}
  • createApplicationContext方法创建容器ConfigurableApplicationContext,根据签名的是否web环境决定是创建AnnotationConfigEmbeddedWebApplicationContext或者AnnotationConfigApplicationContext
  • 创建失败分析器FailureAnalyzers
  • prepareContext 准备环境
	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		listeners.contextLoaded(context);
	}
 
  1. 给容器设置环境
  2. postProcessApplicationContext:beanNameGenerator和resourceLoader
  3. applyInitializers应用容器初始化器ApplicationContextInitializer
  4. ApplicationArguments放到容器中
  5. Banner放到容器中
  6. load方法利用BeanDefinitionLoader加载注解源,此时容器就注册好了所有的注解源相关的BeanDefinition
  • refreshContext 刷新容器,这一步是最重要的进行了容器的刷新,并且注册了ShutdownHook
  • afterRefresh方法中完成所有runner的执行,包括ApplicationRunner和CommandLineRunner。
  • 至此完成容器的创建和初始化
SpringApplicationBuilder

该类提供了配置SpringApplication的快捷方法。在外置容器创建及启动ApplicationContext过程中,我们自定义的SpringBootServletInitializer就可以利用SpringApplicationBuilder定制容器。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号