1. 程式人生 > >SpringBoot原始碼學習(更新中)

SpringBoot原始碼學習(更新中)

最近在專案中運用了Springboot,簡單的學習了簡單的使用,於是想去看看原始碼是如何實現的。

自己也是第一次嘗試看原始碼,結合了網上的東西和自己的理解,在部落格裡寫點東西,做做積累, 如果其中哪些地方解釋有問題,

歡迎老司機指出

參考文章:

1.https://my.oschina.net/u/3081965/blog/916126

2.http://www.cfanz.cn/index.php?c=article&a=read&id=307782

首先不知道從哪裡入手,於是我從專案的啟動入口開始。

以下就是專案入口程式碼,很簡單,由於是在慕課網上學習的,這裡的報名就直接寫imooc了(這個為對應springboot的學習地址:http://www.imooc.com/learn/767)

這邊的spring-boot版本為1.4.7

package com.imooc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GirlApplication {

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

@SpringBootApplication 註解暫時不講,先從下面這個方法開始講起
SpringApplication.run(GirlApplication.class, args);
點選進去可以看到
	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified source using default settings.
	 * @param source the source to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Object source, String... args) {
//第一次進入到達這裡
		return run(new Object[] { source }, args);
	}

	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified sources using default settings and user supplied arguments.
	 * @param sources the sources to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
//上面方法後進入這裡
		return new SpringApplication(sources).run(args);
	}
首先為第一步,第一步呼叫第二部的方法,這裡主要看下第二步。
第二步這邊分為兩個步驟去看,第一個步驟為呼叫SpringApplication類的構造方法建立物件,第二步為呼叫建立物件的run方法,這裡以這兩個步驟進行解讀。
構建物件:
	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified sources (see {@link SpringApplication class-level}
	 * documentation for details. The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param sources the bean sources
	 * @see #run(Object, String[])
	 * @see #SpringApplication(ResourceLoader, Object...)
	 */
	public SpringApplication(Object... sources) {
//呼叫初始化方法
		initialize(sources);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void initialize(Object[] sources) {
//將物件資源存放到sources這個linkedSet下,這裡的sources就是上訴的com.imooc.GirlController物件
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
//這裡暫時沒有看懂,從字面上來看,是判斷是否有web環境
		this.webEnvironment = deduceWebEnvironment();
//例項化Initializer,initializers成員變數,是一個ApplicationContextInitializer型別物件的集合。 
//顧名思義,ApplicationContextInitializer是一個可以用來初始化ApplicationContext的介面。
//初始化ApplicationContext的Initializer程式
//boot包下的META-INF/spring.factories
0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
3 = "org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer"
//autoconfigure下的META-INF/spring.factories
4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
//例項化監聽器
//初始化 ApplicationListener  boot下9個,autoconfigure一個
//0 = "org.springframework.boot.ClearCachesApplicationListener"
//1 = "org.springframework.boot.builder.ParentContextCloserApplicationListener"
//2 = "org.springframework.boot.context.FileEncodingApplicationListener"
//3 = "org.springframework.boot.context.config.AnsiOutputApplicationListener"
//4 = "org.springframework.boot.context.config.ConfigFileApplicationListener"
//5 = "org.springframework.boot.context.config.DelegatingApplicationListener"
//6 = "org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener"
//7 = "org.springframework.boot.logging.ClasspathLoggingApplicationListener"
//8 = "org.springframework.boot.logging.LoggingApplicationListener"
//9 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer"setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//找出main方法的全類名並返回其例項並設定到SpringApplication的this.mainApplicationClass完成初始化
		this.mainApplicationClass = deduceMainApplicationClass();
	}
這裡附上deduceWebEnvironment()方法的實現,其中WEB_ENVIRONMENT_CLASSES的值為
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

private boolean deduceWebEnvironment() {
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return false;
			}
		}
		return true;
	}


上面SpringApplication的初始化動作已經做完了,然後看下run方法裡做了哪些操作。
public ConfigurableApplicationContext run(String... args) {
   
 //StopWatch是一個監視器,主要是用來記錄程式的執行時間,這裡是用來記錄程式啟動所需要的時間
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = 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();
      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);
   }
}