SpringApplication類的直接作用是在main方法中通過自有的run方法啟動spring應用。
具體的run方法為:
public static ConfigurableApplicationContext run(Object source, String... args)
該方法最終會把source傳給SpringApplication的構造方法中的初始化方法:
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(); }
該初始化方法一共做了以下幾件事:
一、判斷sourse長度
首先,如果sources長度大於0(即是數組或容器),則把這些sources全部傳到內置的hashset中。由此可見,run方法的第一個參數中是可以傳入多個source的。
二、判斷web環境是否正確
this.webEnvironment = deduceWebEnvironment();
判斷整個環境中是否存在javax.servlet.Servlet類和
org.springframework.web.context.ConfigurableWebApplicationContext類這兩個類,如果存在話,則表示web環境正常,返回true,否則返回false。
三、設置Initializers
首先會調getSpringFactoriesInstances方法加載ApplicationContextInitializer類,這個方法最終會運行SpringFactoriesLoader.loadFactoryNames方法,這個方法的目的是從“META-INF/spring.factories文件”中加載配置。
可實際上我們一般在開發springboot項目時並沒有創建過spring.factories文件,可還是自動加載了各種配置,原因如下:
在項目的main方法上一般都會設置@SpringBootApplication注解,@SpringBootApplication注解中包含了多個注解,其中有一個@EnableAutoConfiguration注解尤為重要。
通過@EnableAutoConfiguration注解會將org.springframework.boot.autoconfigure.EnableAutoConfiguration這個包作為查找META-INF/spring.factories文件的根目錄,即spring.factories文件會從org.springframework.boot.autoconfigure.EnableAutoConfiguration包中查找。而這個包里面自然有已經寫好的spring.factories文件了。
整個springboot中會看到很多@Enable開頭的注解,所有的@Enable開頭的注解的作用都是通過@Import將“特定的bean”加載到Ioc容器中。@EnableAutoConfiguration的作用就是通過SpringFactoriesLoader將所有的標注了@Configuration注解的類加載(既有boot.autoconfigure包自帶的標注了@Configuration的類,也可以是自己創建的標注了@Configration的類,都會被作為配置加載)
四、設置Listeners
listener的加載與之前的Initializers加載同理,都是尋找META-INF/spring.factories文件,然后被@EnableAutoConfiguration注解把路徑轉移到了org.springframework.boot.autoconfigure.EnableAutoConfiguration/META-INF/spring.factories中,之后就能找到已經提前寫好的相關監聽配置了。
五、設置mainApplicationClass
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
該方法是通過遍歷棧,找到main方法,從而找到啟動類,並將其賦值給mainApplicationClass屬性。
