1. 程式人生 > >springboot啟動 源碼

springboot啟動 源碼

started 邏輯 lee ESS catch failure configure parser proc

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環境,決定生成哪一種contextAnnotationConfigEmbeddedWebApplicationContext

還是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 ConfigurationClassParserparser.parse(candidates);

解析的邏輯是:

對所有的內部類,重新進行parse方法(不嚴謹但是差不多啦)

然後看看自己的類上面有沒有

@PropertySource註解,

@ComponentScan註解:邏輯是:有該註解的類,掃描下面的包,得到一批beanDefinition,然後這批bd出來之後直接用ConfigurationClassUtils.checkConfigurationClassCandidate方法判斷,然後進入processConfigurationClass

方法,但是如果被掃描包裏面,只有@Import註解的類,是不會掃描其中的@Import@Bean等註解的,那說明得到這批beanDefinition的時候,已經過濾了,只掃描有@Component註解的(@Configuration也是包含@Component的)。

具體辦法是:componentScanParser.parse方法中,scanner.doScan方法中findCandidateComponentsisCandidateComponentexcludeFiltersincludeFilters,而默認的filter只會包含@Component或者其他的什麽

@ManagedBeanJSR-330:@Named等等。上面說的scannerClassPathBeanDefinitionScanner,在構造方法中有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啟動 源碼