springboot run()方法系列 --五六七步

版本

本文采用的是springboot 1.5.9版本.

run方法()

重新回顾一下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) {
		//1. 初始化stopwatch,用于计时,本文不详细讲解
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		//2. 设置系统属性java.awt.handless为true,
		//该属性表示系统可以在缺少显示设备、键盘或鼠标这些外设的情况下进行使用,本文不详细讲解。
		configureHeadlessProperty();
		//3. 获得runListeners,并启动(调用listener的onApplicationEvent方法)
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			//4. 创建DefaultApplicationArguments(该类含有args),然后调用prepareEnvironment()
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,					applicationArguments);
			//5. 打印banner
			Banner printedBanner = printBanner(environment);
			//6. 创建Springboot的上下文ApplicationContext
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);
			//7. prepareContext
			prepareContext(context, environment, listeners, applicationArguments,printedBanner);
			//8. spring最出名的refresh()方法
			refreshContext(context);
			//9. TODO
			afterRefresh(context, applicationArguments);
			//10. TODO
			listeners.finished(context, null);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			//11. 处理异常
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}

第五步 打印banner

打印banner相对整个run方法而言没有那么重要,因此只进行一些简单的介绍。
首先,对banner接口进行介绍:

public interface Banner {
	void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);

	enum Mode {
		//关闭banner
		OFF,
		//控制台
		CONSOLE,
		//日志
		LOG

	}
}

Banner接口提供了一个打印banner的方法,然后枚举Mode提供了三种可能的选择方式。Banner接口有以下几个主要的实现类:

  1. ImageBanner:用于打印图片
  2. ResourceBanner:在resource文件夹中创建banner.txt时,ResouceBanner会将该txt里面的内容打印出来,并且还支持解析txt中的占位符${}。

接下来介绍printBanner()方法:

	private Banner printBanner(ConfigurableEnvironment environment) {
		//如果在启动类中设置Banner.Mode.OFF的话,则禁用banner
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		//这里resourceLoader为空,因此会创建一个DefaultResourceLoader
		ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		//LOG的话,则输出到log中
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		//输出到控制台(默认情况)
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

print是按照ImageBanner->ResourceBanner的顺序来进行打印的,具体代码这里便不深入介绍。

第六步 创建ApplicationContext

	public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
		
	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				//1. 因为webEnvironment不为空,所以获取的是web的默认context类
				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);
			}
		}
		//2. 调用BeanUtils.instantiate创建context类
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}

BeanUtils.instantiate(class)实际上就是调用class.newInstance(),无参构造器创建实例:

	public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
		//忽略判断代码
		try {
			return clazz.newInstance();
		}
		catch (InstantiationException ex) {
			...
		}
	}

因此接下来需要去看AnnotationConfigEmbeddedWebApplicationContext类:

	public AnnotationConfigEmbeddedWebApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

可以看到,该类中实际上包含了一个reader和一个scanner,看到这两个类我立即反应过来这个类实际上就是spring中的AnnotationConfigApplicationContext,如果对该类不了解,可以阅读我的另一篇文章:spring 源码系列(四)- AnnotationConfigApplicationContext

第七步 prepareContext

TODO

你可能感兴趣的:(springboot,源码)