本文來自網易雲社區java
上一篇介紹了起步依賴,這篇咱們先來看下SpringBoot項目是如何啓動的。linux
再次觀察工程的Maven配置文件,能夠看到工程的默認打包方式是jar格式的。web
<packaging>jar</packaging>
SpringBoot默認的打包方式爲jar,而且內嵌web容器。所以咱們能夠用運行jar包的方式啓動一個web程序:spring
java -jar xxx.jar
linux服務器上能夠用下面命令讓服務常駐:服務器
nohup java -jar xxx.jar &
咱們知道jar包方式運行須要main方法,SpringBoot已爲咱們自動生成,這個類即是項目啓動入口。app
個人項目名是blog-demo,對應生成的main方法在BlogDemoApplication.java,其代碼以下:框架
@SpringBootApplicationpublic class BlogDemoApplication { public static void main(String[] args) { SpringApplication.run(BlogDemoApplication.class, args); } }
main方法中執行SpringApplication的靜態方法run,並將當前類和啓動參數傳入。less
靜態方法中實例化一個SpringApplication,並調用實例的run方法:spring-boot
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
先來看下調用的SpringApplication的構造方法:工具
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 這裏的primarySources就是咱們傳入的入口類 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推斷應用類型 this.webApplicationType = deduceWebApplicationType(); // 設置初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 設置監聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 頗有意思的方法,經過異常棧獲取應用入口類 this.mainApplicationClass = deduceMainApplicationClass(); }
注意咱們傳入的啓動類被保存到了primarySources變量中,將做爲後續context加載beans時的資源,其餘細節再也不展開。
接着看實例的run方法:
/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */public ConfigurableApplicationContext run(String... args) { // 計時工具 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 應用上下文 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); // 設置系統參數-無圖形化界面 // 獲取監聽器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); // 建立上下文 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 上下文前置處理,這裏會解析咱們傳入的入口類 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新上下文 refreshContext(context); // 後置處理 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, listeners, exceptionReporters, ex); throw new IllegalStateException(ex); } listeners.running(context); return context; }
經過方法註釋也能夠看出來該run方法引起了一系列複雜的內部調用和加載過程,從而建立了一個SpringContext。
在prepareContext方法中會解析咱們傳入的入口類,解析其上的註解。下面來看下入口類上的註解。
入口類上的註解@SpringBootApplication是SpringBoot自動配置的關鍵。其定義以下:
@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 { ... }
說明它是@ComponentScan、@SpringBootConfiguration和@EnableAutoConfiguration三個註解的組合。
@ComponentScan是Spring框架原有的註解,在spring-context組件下,用來開啓自動掃描Bean並解析註解注入。
能夠用basePackages指定掃描的包,缺省狀況下默認掃描被註解類所在的包。SpringBoot項目中通常會將入口類放在頂層目錄,這樣默認就會掃描整個項目。
@SpringBootConfiguration是SpringBoot新增的註解,在spring-boot組件下,定義以下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration { }
至關於註解@Configuration,配備了該註解的類就可以以JavaConfig的方式完成一些配置,能夠再也不使用XML配置。
因此在入口類內也能夠以JavaConfig的方式定義Bean。
@EnableAutoConfiguration是SpringBoot新增的註解,在spring-boot-autoconfigurate組件下,它是SpringBoot開啓自動配置的關鍵。放到下一節再講。
這一節簡單解析了SpringBoot的入口類,一個由SpringBoot自動生成的java類,雖然只有短短几行代碼,卻引起了Spring上下文的建立的一系列事件。
首先SpringBoot將入口類傳入做爲資源的起點,當解析到入口類的時候發現其上的註解又開啓了自動配置和包掃描,這樣咱們自定義的Bean就會被加載進去完成建立和依賴。
網易雲新用戶大禮包:https://www.163yun.com/gift
本文來自網易實踐者社區,經做者金港生受權發佈。