Spring Boot 快速入門
一、Spring Boot 簡介
Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化Spring應用
的初始搭建以及開發過程。該框架使用了特定的方式來進行配置(約定優於配置)
,從而使開發人員不再需要定義樣板化的配置。
個人認爲,springboot 並非全新的框架,而是對spring框架的再封裝,通過 starter 的方式輕鬆集成第三方的框架,集成一個框架只需要引入一個 starter,去掉了 XML 的配置,全部用註解代替,然後在屬性文件中配置一些值,整個集成的過程就結束了。總的來說,使用springboot框架可以非常方便、快捷的進行spring項目的開發,提高我們開發的效率。
二、springBoot特點
- 創建獨立的Spring應用程序
- 嵌入的Tomcat,無需部署WAR文件
- 簡化Maven配置
- 自動配置Spring
- 提供生產就緒型功能,如指標,健康檢查和外部配置
- 絕對沒有代碼生成和對XML沒有要求配置
三、使用 IDEA 的 Spring Initializr 創建 springboot 項目
使用 IDEA Spring Initializr 創建項目,可以非常方便的創建一個 spring 項目,真正做到 just run
。
1、開發環境
-
–jdk1.8:Spring Boot 推薦jdk1.7及以上;java version “1.8.0_152”
-
–maven3.x:maven 3.3以上版本;Apache Maven 3.6.1
-
–IntelliJ IDEA:IntelliJ IDEA 2020.1
使用IDEA Spring Initializr創建項目其實就是集成了springboot官網提供的
Spring Initializr模板來創建項目,是需要連接網絡的,如果沒有網絡,建議使用maven方式創建項目。
2、點擊文件 -> 新建 -> 項目
由於使用了IntelliJ IDEA官方提供的中文插件,所以顯示的是中文,我發現換成中文後,自己反而好不習慣,後面已經改回英文了。。。
3、選擇 Spring Initializr ,選擇JDK
需要注意的是springboot只支持 jdk 1.8及以上版本
4、填寫項目信息
springboot框架內嵌了Tomcat和Jetty容器,直接打成jar包也可直接運行,spring-boot-starter-web默認使用Tomcat容器運行,如需切換爲Jetty容器,只需在POM文件中添加Jetty的依賴即可。
5、選擇需要的依賴包
6、選擇存放項目的路徑
需要注意的是,這裏有可能會生成項目失敗,原因是因爲連接https://start.spring.io/網站超時,多嘗試幾次即可。
7、項目創建成功
看到這個界面,我們的第一個springboot項目就創建成功了(可以直接啓動,默認地址爲localhost:8080)。是不是很開心。。。
四、Hello World
上面我們創建了一個springboot的項目,已經可以成功運行了,只是項目裏面什麼都沒有,接下來我們來編寫一個hello world程序,並在瀏覽器中訪問。
1、編寫HelloController
package com.xiaoming.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "Hello World!";
}
}
2、啓動程序
編寫好我們的controller類,我們就可以運行,並且從瀏覽器訪問了,是不是so easy。簡直不要太簡單了。
那麼如何啓動程序呢,我們需要找到程序的主入口類,在本篇就是SpringBootHelloApplication.class,
(需要注意的是,在一個項目中,主入口類有且只能有一個)
,運行main方法即可。
3、頁面訪問
在瀏覽器中請求 localhost:8080/hello 地址,頁面就會給我們顯示出 Hello World! ,到這裏一個入門程序就已經完成了,各位程序猿,沖沖衝!!!
4、修改啓動端口和根路徑
在實際的開發中,程序的端口號是需要根據實際需求改動的,並且一般訪問路徑上需要帶上項目的名稱。此時我們需要修改springboot的默認端口和根路徑的配置,springboot提供了一個全局的配置文件給我們修改springboot自動配置的默認值。配置文件的名字是固定:(本人更喜歡yml格式的配置文件)
•application.properties
•application.yml
關於配置文件就不在這裏細說了,springboot配置相關的知識點我會再寫一篇博客。
如何修改配置文件呢,我們只需要將我們的application.properties文件先改名爲application.yml(不改也行,當然不該的格式和這裏不同),然後在配置文件中加入如下代碼即可:
server:
port: 8888
servlet:
context-path: /xiaoming
修改完成重新啓動一下程序,可以看到我們的端口號和根路徑都變成了我們配置文件中的值。
五、揭開 springboot 的神祕面紗
在上面我們創建並運行了一個 springboot 項目,我們什麼都沒有配置,他憑什麼就能夠正常運行呢?相信各位小夥伴肯定是比較疑惑的。下面我們就來探究一下 springboot 爲什麼能夠這麼便捷的運行起來。
1、POM文件
既然我們的項目是一個maven項目,那麼我們就先來看看程序的 POM 文件裏面長什麼樣吧。
1)、parent 父工程
打開 POM 文件,我們可以在文件的頭部位置看到一個 parent 項目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
這個項目有什麼作用呢?
-
依賴的版本控制
我們繼續查看他的POM文件,點進去可以看到他又有一個 parent 工程
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.7.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent>
繼續點進去,我們發現這個工程裏面保存了基本的依賴和版本的定義,如下圖
可以說這個項目是Spring Boot的版本仲裁中心,真正管理Spring Boot應用裏面的所有依賴版本。所以我們導入依賴默認是不需要寫版本(沒有在這個項目裏面管理的依賴自然還是需要聲明版本號),媽媽再也不擔心我們在開發大型項目時因爲依賴衝突產生的問題了。
-
定義了 Java 編譯版本爲 1.8
回到 spring-boot-starter-parent 工程,還可以看到如下內容:
<properties> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- 這也是爲什麼我們的jdk環境爲什麼需要1.8及以上了 --> <java.version>1.8</java.version> <resource.delimiter>@</resource.delimiter> <maven.compiler.source>${java.version}</maven.compiler.source> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>${java.version}</maven.compiler.target> </properties>
-
設置使用 UTF-8 格式編碼。
-
執行打包操作的配置。
-
自動化的資源過濾。
-
自動化的插件配置。
-
針對 application.properties 和 application.yml 的資源過濾,包括通過 profile 定義的不同環境的配置文件,例如 application-dev.properties 和 application-dev.yml。
<resources> <resource> <filtering>true</filtering> <directory>${basedir}/src/main/resources</directory> <includes> <include>**/application*.yml</include> <include>**/application*.yaml</include> <include>**/application*.properties</include> </includes> </resource> <resource> <directory>${basedir}/src/main/resources</directory> <excludes> <exclude>**/application*.yml</exclude> <exclude>**/application*.yaml</exclude> <exclude>**/application*.properties</exclude> </excludes> </resource> </resources>
2)、啓動器
接着往下查看項目導入的依賴,可以看到以下內容
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
可以發現其中有兩個依賴,一個是我們自己導入的 spring-boot-starter-web 依賴,另一個則是 Spring Initializr 創建項目時自動導入的測試依賴包(細心的小夥伴是不是已經發現了我們導入的依賴都沒有標明版本號)。我們主要關注我們自己導入的 spring-boot-starter-web 依賴包。
我們發現兩個依賴都有類似的名稱
spring-boot-starter-xxx
,其中我們稱spring-boot-starter
爲springboot啓動器,其實就是一系列依賴描述的組合信息,當我們需要用到那個模塊,我們只需要導入那個模塊的啓動器即可,springboot會自動的幫我們導入該模塊需要的一系列組件,並且有 parent 工程定義導入組件的版本,保證我們的程序能夠正常運行
點進 spring-boot-starter-web 項目的 POM 文件,不出所料,spring-boot-starter-web 啓動器幫我們導入了一系列的依賴包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.2.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 這裏可以看出爲什麼我們的程序默認使用Tomcat容器運行 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.2.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.2.7.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>tomcat-embed-el</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
2、主入口類
我們開發任何一個Spring Boot項目,項目中都會有且只有一個啓動類,如下
package com.xiaoming.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootHelloApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloApplication.class, args);
}
}
從上面代碼可以看出,我們需要關注的點有兩個,一個是@SpringBootApplication
註解,另一個就是main方法中的SpringApplication.run()
語句。
1)、@SpringBootApplication
@SpringBootApplication註解是Spring Boot的核心註解,它標註在某個類上就說明這個類是Spring Boot應用的主配置類,SpringBoot就應該運行這個類的main方法來啓動Spring Boot應用;我們點進這個註解中可以發現@SpringBootApplication註解其實是多個註解的組合。
@Target(ElementType.TYPE) // 註解的適用範圍,其中TYPE用於描述類、接口(包括包註解類型)或enum聲明
@Retention(RetentionPolicy.RUNTIME) // 註解的生命週期,保留到class文件中(三個生命週期)
@Documented // 表明這個註解應該被javadoc記錄
@Inherited // 子類可以繼承該註解
@SpringBootConfiguration // 繼承了Configuration,表示當前是註解類
@EnableAutoConfiguration // 開啓springboot的註解功能,springboot的四大神器之一,其藉助@import的幫助
@ComponentScan(excludeFilters = { // 包掃描路徑
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
...
}
雖然定義使用了7個註解進行了原信息標註,但實際上重要的只有三個註解:
- @SpringBootConfiguration(點開查看發現裏面還是應用了@Configuration註解)
- @EnableAutoConfiguration
- @ComponentScan
我們可以這樣認爲:@SpringBootApplication ≈ @Configuration + @EnableAutoConfiguration + @ComponentScan
如果我們不嫌麻煩的話,我們的啓動類也可以寫成這樣子
package com.xiaoming.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class SpringBootHelloApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloApplication.class, args);
}
}
可以看到,運行效果和@SpringBootApplication是一樣
2)、@SpringBootConfiguration
@SpringBootConfiguration註解標註在某個類上,表示這是一個Spring Boot的配置類,底層使用的是@Configuration註解,需要注意的是,配置類本身也是IOC容器中的一個組件。
3)、@ComponentScan
@ComponentScan這個註解在Spring中很重要,它的功能其實就是自動掃描並加載符合條件的組件(比如@Component和@Repository等)或者bean定義,最終將這些bean定義加載到IOC容器中。
注意:如果你的其他包都在使用了@SpringBootApplication註解的main app所在的包及其下級包,則你什麼都不用做,SpringBoot會自動幫你把其他包都掃描了。
如果你有一些bean所在的包,不在main app的包及其下級包,那麼你需要手動加上@ComponentScan註解並指定那個bean所在的包。
所以SpringBoot的啓動類最好是放在root package下,因爲默認不指定basePackages。
4)、@EnableAutoConfiguration
@EnableAutoConfiguration 註解告訴Spring Boot開啓自動配置功能,這樣自動配置才能生效。他的底層是使用@Import註解,將所有符合自動配置條件的bean定義加載到IOC容器。
@EnableAutoConfiguration作爲一個複合Annotation,其自身定義關鍵信息如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
其中主要的註解就是,@AutoConfigurationPackage和 @Import(EnableAutoConfigurationImportSelector.class)
-
@AutoConfigurationPackage
的底層其實也是調用了 @Import(AutoConfigurationPackages.Registrar.class) 註解@Import(AutoConfigurationPackages.Registrar.class)
的其實就是由AutoConfigurationPackages.Registrar類將主配置類所在包及下面所有子包裏面的所有組件掃描並註冊到IOC容器中
-
@Import(EnableAutoConfigurationImportSelector.class)
中的EnableAutoConfigurationImportSelector就是自動配置導入選擇器,它來決定那些組件能夠被導入進去,它會將所有需要導入的組件以全類名的方式返回,返回的組件就會別添加到IOC容器中。// springboot 獲取自動配置類的源碼 protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
進入源碼debug查看返回了那些類,如下圖
我們發現
@Import(EnableAutoConfigurationImportSelector.class)
會給容器中導入非常多的自動配置類(xxxAutoConfiguration),就是給容器中導入這個場景需要的所有組件,並配置好這些組件,有了這些自動配置類,就免去了我們手動編寫配置注入功能組件的工作;在 getAutoConfigurationEntr() 方法中調用了一個非常關鍵的方法,就是 getCandidateConfigurations(),源代碼如下
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.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
就是我們能夠獲取到這麼多自動配置類的關鍵。SpringFactoriesLoader屬於Spring框架私有的一種擴展方案,其主要功能就是從指定的配置文件META-INF/spring.factories加載配置。
配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查找的功能支持,即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作爲查找的Key,獲取對應的一組@Configuration類。我們去到源代碼查看,如下圖
所以,@EnableAutoConfiguration自動配置就是:從classpath中搜尋所有的META-INF/spring.factories配置文件,並將其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的配置項通過反射實例化爲對應的標註了@Configuration的JavaConfig形式的IOC容器配置類,然後彙總爲一個並加載到IOC容器中。
(詳細的自動配置原理,我會放到springboot配置相關的博客中講解的,邊學習springboot邊寫博客,讓自己理解的更加透徹一點,嘻嘻嘻)在上面編寫的Hello World程序中我們添加了spring-boot-starter-web啓動器,程序會自動添加Tomcat和Spring MVC的依賴,然後Spring Boot就會對Tomcat和Spring MVC進行自動配置。
看到這裏各位小夥伴心中的疑惑是不是已經解開了呢?明明我們什麼都沒有配置,程序卻能正常運行,其實和我們用spring開發時的配置相比一樣沒少,只不過是springboot將以前需要我們程序猿配置的東西,自動配置好了,真正做到了 “just run”。這就是 springboot 這麼火爆的理由之一吧。
感謝你看到這裏