Spring Boot的初始化時從一個main方法開始,進入調用到SpringApplication的內部去實現java
首先調用的是web
進入這個類的內部就是spring
繼續tomcat
核心就是從這個new方法開始,run(args)開始執行各類初始化環境的操做springboot
首先咱們來看這個構造方法app
這個方法調用的是initialize方法區初始化各類須要的條件環境less
private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } //經過判斷是否能加載到Servlate跟ConfigurableWebApplicationContext這個類去判讀是否爲web環境 this.webEnvironment = deduceWebEnvironment(); //讀取spring.factories文件中的org.springframework.context.ApplicationContextInitializer對應的各類類名,而後加載內存建立好,爲了下面使用 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); //讀取spring.factories文件中的org.springframework.context.ApplicationListener對應的各類類名,而後加載內存建立好,爲了下面使用 setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class)); //肯定main方法所在的類 this.mainApplicationClass = deduceMainApplicationClass(); }
以一個方法爲例子this
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 //這是根據spring.facotories文件獲得的value都是一些SpringApplicationRunListener的實現類的全類名稱 Set<String> names = new LinkedHashSet<String>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //加載到內存並初始化實例 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //根據實例的名稱排序 AnnotationAwareOrderComparator.sort(instances); return instances; }
值得小注意的是:Spring使用的是線程上下文加載器,去加載的本身的各個模塊的jar中的類,由於爲了確保加載器必定是當前容器的加載器,才能夠加在到這些Class文件的,好比當前的環境是web環境,並且是tomcat的容器,因此這些jar文件是經過的tomcat的的類加載去加載的,而默認的線程上下文加載就是自定義的tomcat容器加載器,因此須要這樣去加載Class,其實就是經過類加載器能夠更換咱們想要的加載器spa
下面就是簡單的根據ClassLoader還有Class類型去加載類文件到內存,而後實例化的過程,而後返回這些實例對象線程
當須要的ApplicationContextInitializer、ApplicationListener實現類加載完成後,都會保存到SpringApplication這個類的對應的Map中
//保存ApplicationContextInitializer實現類的實例對象 public void setInitializers( Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<ApplicationContextInitializer<?>>(); this.initializers.addAll(initializers); } //保存ApplicationListener實現類的的實例對象 public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<ApplicationListener<?>>(); this.listeners.addAll(listeners); }
大概加載流程以下
至此springboot創造一個SpringApplication這個類,準備了實例化各類配置參數類,而後進入到真正的建立SpringContext整個環境的入口
public ConfigurableApplicationContext run(String... args) { //建立一個監聽類StopWacht,記錄啓動的時間,加載類等信息輸出到log StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; //用來設置java.awt.headless 屬性是true 仍是false,是J2SE的一種模式用於在缺乏顯示屏、鍵盤 //或者鼠標時的系統配置 configureHeadlessProperty(); //讀取spring.factory中配置初始化EventPublishingRunListener這個類 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); } }