springboot启动流程分析

springboot启动有两种方式:

1:直接使用静态方法启动

SpringApplication.run(App.class,args);

2:创建SpringApplication实例以后,调用实例的方法启动

SpringApplication app = new SpringApplication(App.class);
ConfigurableApplicationContext context = app.run(args);

我们观看静态方法的源码就可以发现,静态方法的实现实际上是使用方式2创建实例启动的

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
	return new SpringApplication(sources).run(args);
}
SpringApplication构造的时候会执行initialize初始化方法,该方法主要作用为:
(1)deduceWebEnvironment(); 判断是否是web环境  
(2)setInitializers(...); 从所有jar包下的META-INF/spring.factories文件中获取所有ApplicationContextInitializer类型的值,实例化后加入ApplicationContextInitializer的集合。
(3)setListeners(...);从所有jar包下的META-INF/spring.factories文件中获取所有ApplicationListener类型的值,实例化后加入ApplicationListener的集合。ApplicationListener:监听容器中发布的事件。
    可参考:https://blog.csdn.net/liyantianmin/article/details/81017960
(4)deduceMainApplicationClass(...); 确定main方法所在的类并实例化。
public SpringApplication(Object... sources) {
		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();
	}

 

下面开始具体分析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;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.started();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			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, ex);
			throw new IllegalStateException(ex);
		}
	}

 1、stopWatch.start();

       说明:辅助功能,可不计入流程。该方法主要判断springboot是否已经启动,如果没有则记录下开始启动的系统时间,方便计算整个启动过程共用了多少时长。

public void start(String taskName) throws IllegalStateException {
        if(this.running) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        } else {
            this.running = true;
            this.currentTaskName = taskName;
            this.startTimeMillis = System.currentTimeMillis();
        }
    }

2、configureHeadlessProperty();

       说明:方法名称告诉我们该方法配置Headless属性,Headless模式是在缺少显示屏、键盘或者鼠标是的系统配置。该方法确保Headless属性有值,如果系统中没有则设置为true(初始化变量值默认为true:private boolean headless = true;),如果已经设置则用设置的值。

      如果名字为 java.awt.headless 的系统属性被设置true,那么 headless 工具包就会被使用。应用程序可以执行如下操作:

  1. 创建轻量级组件。
  2. 收集关于可用的字体、字体指标和字体设置的信息。
  3. 设置颜色来渲染准备图片。
  4. 创造和获取图像,为渲染准备图片。
  5. 使用java.awt.PrintJob,java.awt.print和javax.print类里的打印

       详细可参考:
       https://www.cnblogs.com/wangxuejian/p/10603034.html

       https://www.liangzl.com/get-article-detail-149808.html

private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
				SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

3、SpringApplicationRunListeners listeners = getRunListeners(args);

      listeners.started();

      说明:该方法主要是遍历整个ClassLoader中所有jar包下的META-INF/spring.factories文件,SpringFactoriesLoader会加载文件中所有类型为SpringApplicationRunListener的类名,创建实例放入SpringApplicationRunListener集合中排序。然后调用所有实例的启动方法。SpringApplicationRunListener主要用来监听Spring Boot的启动流程,可以实现该接口自定义处理逻辑:     

package org.springframework.boot;
public interface SpringApplicationRunListener {

    // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
    void starting();
    // 当environment构建完成,ApplicationContext创建之前,该方法被调用
    void environmentPrepared(ConfigurableEnvironment environment);
    // 当ApplicationContext构建完成时,该方法被调用
    void contextPrepared(ConfigurableApplicationContext context);
    // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
    void contextLoaded(ConfigurableApplicationContext context);
    // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
    void started(ConfigurableApplicationContext context);
    // 在run()方法执行完成前该方法被调用
    void running(ConfigurableApplicationContext context);
    // 当应用运行出错时该方法被调用
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

      关于SpringApplicationRunListener的详细内容可查阅:https://www.jianshu.com/p/b86a7c8b3442

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }

4、ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);

     说明:根据run方法传入的args参数,实例化ApplicationArguments对象。

5、ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

     说明:准备运行时的环境。     

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		if (isWebEnvironment(environment) && !this.webEnvironment) {
			environment = convertToStandardEnvironment(environment);
		}
		return environment;
	}

     详细可参考:https://blog.csdn.net/lz710117239/article/details/80104519

6、printBanner(environment);

    说明:控制栏打印启动开头时的banner,显示启动效果。

7、createApplicationContext();     

    说明:实例化ConfigurableApplicationContext对象。

    web环境创建:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext

    否则创建:org.springframework.context.annotation.AnnotationConfigApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}

8:prepareContext(context, environment, listeners, applicationArguments, printedBanner);     

     说明:准备context。

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<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		listeners.contextLoaded(context);
	}
饿了,恰饭,后续待续...
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值