此文讓你明白springboot啓動原理

緣起

如今的項目都是springboot的了,相比以前的ssm或者ssh項目,springboot採用約定大於配置模式項目搭建特別簡單,並且springboot項目的開發效率也提高了好幾倍。只需在SpringApplication運行run方法,就能夠運行springboot項目,可是不少人就只瞭解到這裏了,徹底不瞭解springboot背後是怎麼作到的。因此就跟隨着我根據源碼來一塊兒探索這背後的原理吧。web

啓動類分析

/** Spring Boot應用啓動類* Created by fqh on 17/6/24.*/@SpringBootApplication@ComponentScan("com.wish.platform")public class Application{/*** 無 applicationContext.xml 和 web.xml, 靠下述方式進行配置:* 1. 掃描當前package下的class設置自動注入的Bean* 2. 也支持用@Bean標註的類配置Bean* 3. 根據classpath中的三方包Class及集中的application.properties條件配置三方包,如線程池* 4. 也支持用@Configuration標註的類配置三方包.*/public static void main(String[] args) {SpringApplication.run(Application.class, args);}}

上面是一個比較標準的springboot啓動類,比較扎眼的的地方其實就兩個spring

  1. 註解 @SpringBootApplicationspringboot

  2. main中的SpringApplication.run(Application.class, args); 
    咱們挨個進行分析,一層層的揭開這神祕的面紗 
    首先@SpringBootApplication,點擊源碼查看app

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {...略...}

一紮眼看好多註解,可是實際上重要的就幾個,(PS: @Inherited是註解子類能夠繼承 @Documented只是用於生成文檔注視)框架

  1. @SpringBootConfigurationless

  2. @EnableAutoConfigurationssh

  3. @ComponentScan 
    因此從這裏咱們能夠判斷出,一個@SpringBootApplication等於上述三個註解。ide

1、分析@SpringBootApplication

  1. @SpringBootConfiguration解析 
    這個點擊進去發現,其實這個就是個@Configuration工具

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {}

Configuration應該不陌生了把。spring爲了減小xml配置,從版本3.0開始提供了@Configuration配合@Bean用於在JavaConfig類上進行標註,用於代替xml的配置。例如: 

Configuration 
public class DaoConfig{ 
Bean 
public UserDao userDao(){ return new UserDaoImpl();} 
Bean 
public BookDao bookDao(){return new BookDaoImpl();} 
} 

若是一個bean的定義依賴其餘bean,則直接調用對應的JavaConfig類中依賴bean的建立方法就能夠了。測試

  1. @ComponentScan解析 
    做用就是在指定的目錄下(basePackages屬性控制)自動掃描複合加載條件的bean(包括@Compoent,@Controller,@Repository),並最終把這些bean加入到spring的IOC容器裏.

  2. @EnableAutoConfiguration解析 
    源碼:

@SuppressWarnings("deprecation")@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";...其餘略..}

重點來了,發現EnableAutoConfiguration是一個複合Annotation,關鍵的組合註解以下:

  • @AutoConfigurationPackage :標註自動配置包

  • @Import(EnableAutoConfigurationImportSelector.class) :最重要的 
    藉助於EnableAutoConfigurationImportSelector,能夠幫助springboot程序將全部複合條件的@Configuration配置都加載到 由當前springboot建立使用的IOC容器中,保證全部實例都 
    能夠在一個ApplicationContext裏 
    EnableAutoConfigurationImportSelector類裏有這麼幾個方法都用到了SpringFactoriesLoader這個spring框架的工具類

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,this.beanClassLoader);}/*** Return the auto-configuration class names that should be considered. By default* this method will load candidates using {@link SpringFactoriesLoader} with* {@link #getSpringFactoriesLoaderFactoryClass()}.* @param metadata the source metadata* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation* attributes}* @return a list of candidate configurations*/protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}

藉助於SpringFactoriesLoader的支持,@EnableAutoConfiguration 才能夠智能的實現自動配置! 
這裏再簡單介紹一下SpringFactoriesLoader,這是spring的本身的擴展方案,主要經過META-INF/spring.factories加載配置 
搜索之後能夠看到不少spring相關的jar裏都有這個文件,

圖片

隨便打開一個

圖片

發現key是一個接口類,value是具體的一個或者一組實現類。

總結:這樣@EnableutoConfiguration配合SpringFactoriesLoader,就是從classpath裏搜索全部的META-INF/spring.factories配置文件,並將配置文件的配置項key接口類 經過反射 實例化全部value的實現類。而後這些實例化的類都彙總加載到當前springboot 上下文的IOC容器中

2、分析SpringApplication.run(Application.class, args)

追蹤源碼,能夠看到SpringApplication的靜態run方法實際上返回的是ApplicationContext,具體中間實現過程能夠看一下代碼,我加了一些注視,方便你們理解

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();//提供一組方法和屬性,可用於準確地測量運行時間。stopWatch.start();//計時開始ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;this.configureHeadlessProperty();SpringApplicationRunListeners listeners = this.getRunListeners(args);//獲取springboot運行時監聽listeners.starting();//監聽開始try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);//獲取運行時環境(就是你設置的profile,開發環境,測試環境這些)Banner printedBanner = this.printBanner(environment);//springboot的bannner信息,佛祖保佑context = this.createApplicationContext();//建立上下文new FailureAnalyzers(context);this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);//根據當前context,profile,參數,banner,來預處理上下文(說白了就是把這些參數都對應賦值到上下文上)。this.refreshContext(context);//根據上下文參數來判斷建立什麼類型的上下文,根據條件決定是否添加ShutDownHook鉤子。this.afterRefresh(context, applicationArguments);//最核心的一步,把全部經過EnableAutoConfiguration獲取的實例添加到一個IOC容器裏,而且都添加到當前的上下文ApplicationContext裏listeners.finished(context, (Throwable)null);//最後一道,結束監聽stopWatch.stop();//能夠計算出啓動時間if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}return context;} catch (Throwable var9) {this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);throw new IllegalStateException(var9);}}

結束語

到此,SpringBoot的核心組件完成了基本的解析,綜合來看,大部分都是Spring框架背後的一些概念和實踐方式,SpringBoot只是在這些概念和實踐上對特定的場景事先進行了固化和昇華,而也偏偏是這些固化讓咱們開發基於Sping框架的應用更加方便高效。PS:但願我這個花了三四個小時才寫完的文章,能給你帶來深刻的啓發!

相關文章
相關標籤/搜索