springboot啟動 源碼
public ConfigurableApplicationContext run(String... args) {
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();//邏輯是,判斷是不是web環境,決定生成哪一種context,AnnotationConfigEmbeddedWebApplicationContext,
還是AnnotationConfigApplicationContext
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);//最關鍵的一個方法load()是把啟動類給註冊到工廠裏
refreshContext(context);//在AnnotationConfigEmbeddedWebApplicationContext的構造函數中,new AnnotatedBeanDefinitionReader(this),而這個構造方法中
會向工廠註冊(註意註冊和實例化不同)ConfigurationClassPostProcessor(其他PostProcessor先不說),在本方法中,refresh工廠的時候,在invokeBeanFactoryPostProcessors這一步,
會調用所有實現BeanFactoryPostProcessor接口和BeanDefinitionRegistryPostProcessor接口的類的兩個相應方法,
@Configuration註解的解析:
上面的兩個方法都最終會執行processConfigBeanDefinitions方法,邏輯是判斷所有已經註冊的beanname,上面有沒有註解@Configuration,如果有的話,用ConfigurationClassParser解析
parser = new ConfigurationClassParser,parser.parse(candidates);
解析的邏輯是:
對所有的內部類,重新進行parse方法(不嚴謹但是差不多啦)
然後看看自己的類上面有沒有
@PropertySource註解,
@ComponentScan註解:邏輯是:有該註解的類,掃描下面的包,得到一批beanDefinition,然後這批bd出來之後直接用ConfigurationClassUtils.checkConfigurationClassCandidate方法判斷,然後進入processConfigurationClass
方法,但是如果被掃描包裏面,只有@Import註解的類,是不會掃描其中的@Import,@Bean等註解的,那說明得到這批beanDefinition的時候,已經過濾了,只掃描有@Component註解的(@Configuration也是包含@Component的)。
具體辦法是:componentScanParser.parse方法中,scanner.doScan方法中findCandidateComponents中isCandidateComponent的excludeFilters和includeFilters,而默認的filter只會包含@Component或者其他的什麽
@ManagedBean、JSR-330:@Named等等。上面說的scanner是ClassPathBeanDefinitionScanner,在構造方法中有registerDefaultFilters();
其實這樣看起來,@configuration@SpringBootConfiguration註解沒啥用,完全可以用@component代替///@EnableAutoConfiguration其實是兩個@Import註解的組合,一個導入AutoConfigurationImportSelector.class,一個通過
@AutoConfigurationPackage導入AutoConfigurationPackages.Registrar.class
@Import註解:先根據@Import註解裏面的值,看該類上面有沒有@Import註解,如果有,也加入進來,然後對於所有的候選類,如果是ImportSelector,或者ImportBeanDefinitionRegistrar,如果都不是,那麽當作@Configuration
@ImportResource註解,
@Bean註解,
然後看它的父類,parse父類(也不嚴謹但是也差不多啦),直到父類以java開頭?
所以這裏可以看出,對類上面有沒有@Configuration的判斷,只在當前類上進行,而它的內部類和父類,都不做判斷。那麽一個@Configuration的類,它的內部類和父類,都要判斷裏面的註解類型
最後,會放到 工廠的 configurationClasses屬性中
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);
}
}
springboot啟動 源碼