本系列教程根據(jù)本人實際學習使用 SpringBoot2.x 過程總結整理而來点楼。
1扫尖、Spring Boot 簡介
Spring Boot 用來簡化 Spring 應用開發(fā),約定大于配置掠廓,刪繁就簡换怖,just run 就能創(chuàng)建一個獨立的、產品級的應用
-
出現(xiàn)背景:
J2EE(例如 Spring ) 笨重的開發(fā)蟀瞧、繁多的配置沉颂、低下的開發(fā)效率、負責的部署流程和第三方技術集成難度大黄橘。
-
解決方案:
“Spring 全家桶” 時代:
Spring Boot → J2EE 一站式解決方案
Spring Cloud → 分布式整體解決方案
-
優(yōu)點:
快速創(chuàng)建獨立運行的 Spring 項目以及與主流框架集成
使用嵌入式的 Servlet 容器兆览,應用無需打成 war包
starters 自動依賴于版本控制
大量的自動配置,簡化開發(fā),也可以修改默認屬性值
開箱即用馋辈,無需配置 xml硫戈,無代碼生成
生產環(huán)境的運行時應用監(jiān)控
與云計算天然集成
總結:
- 簡化Spring應用開發(fā)的一個框架茶敏;
- 整個Spring技術棧的一個大整合小压;
- J2EE開發(fā)的一站式解決方案线梗;
2、微服務
- 2014由martin fowler提出
- 微服務:架構風格(服務微化)
- 一個應用應該是一組小型服務怠益;可以通過HTTP的方式進行互通仪搔;
- 單體應用:ALL IN ONE
- 微服務:每一個功能元素最終都是一個可獨立替換和獨立升級的軟件單元;
- 詳細參照微服務文檔
單體應用:
微服務:
3蜻牢、環(huán)境準備
開發(fā)環(huán)境:
- jdk1.8:Spring Boot 推薦jdk1.7及以上烤咧;java version "1.8.0_221"
- maven3.x:maven 3.3以上版本;apache-maven-3.6.1
- IntelliJIDEA2019:IntelliJ IDEA 2019.1.3 x64
- SpringBoot 2.2.1.RELEASE:2.2.1抢呆;
開發(fā)配置:
1煮嫌、MAVEN設置:
給 maven 的 settings.xml
配置文件的 profiles
標簽添加下面的配置,設置 maven 的創(chuàng)建項目時的默認編譯版本使用 jdk8
<profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>
2抱虐、IDEA設置:
Idea 整合 Maven:
4昌阿、創(chuàng)建 Spring Boot HelloWorld
1、快速開始
首先我們先創(chuàng)建一個統(tǒng)一的 maven 工程恳邀,用來管理我們之后學習中所有的項目:
1懦冰、新建項目
2、選擇Maven項目
3谣沸、填寫GroupId刷钢、ArtifactId
GroupId:com.demo.springboot
ArtifactId:SpringBoot-In-Action
5、填寫項目名和項目路徑
6鳄抒、創(chuàng)建一個空的maven項目完成闯捎,選擇允許自動導入
7、刪除多余的目錄
只保留一個pom.xml文件即可许溅,同時在pom文件中添加springboot依賴和打包類型
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<packaging>pom</packaging>
2瓤鼻、現(xiàn)在開始我們的 Spring Boot HelloWorld 項目:
一個功能:瀏覽器發(fā)送hello請求,服務器接受請求并處理贤重,響應Hello World字符串
茬祷;
1、創(chuàng)建一個maven工程并蝗;(jar)
在SpringBoot-In-Action項目中新建一個module,選擇maven工程祭犯,命名為 spring-boot-01-helloworld
2、導入spring boot相關的依賴
因為springboot的依賴已經在父pom中導入
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
所以在當前的pom中只需要導入spring-boot-starter-web的依賴即可:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
完整 pom
文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringBoot-In-Action</artifactId>
<groupId>com.demo.springboot</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-01-helloworld</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
3滚停、編寫一個主程序沃粗;啟動Spring Boot應用
/**
* @SpringBootApplication 來標注一個主程序類,說明這是一個Spring Boot應用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring應用啟動起來
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
4键畴、編寫相關的Controller最盅、Service
為了演示突雪,我在這里只創(chuàng)建了 Controller
類,省略了 Service
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello() {
return "Hello World!";
}
}
5涡贱、運行主程序測試效果
選中 HelloWorldMainApplication
右鍵單擊選擇 Run ...
咏删,或者打開 HelloWorldMainApplication
按下快捷鍵 Ctrl+Shift+F10
運行程序,可以看到項目在 8080
端口啟動:
在瀏覽器中訪問 http://localhost:8080/hello 可以看到正常返回了 Hello World
问词。
至此督函,我們的第一個 Spring Boot 項目算是創(chuàng)建完了。
6激挪、補充:簡化部署
在當前項目辰狡,即 spring-boot-01-helloworld
的 pom
文件中添加下面的配置
<!-- 這個插件,可以將應用打包成一個可執(zhí)行的jar包垄分;-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
然后選中當前 pom
文件搓译,右鍵單擊,選擇 Run Maven
→ package
锋喜,將這個應用打成 jar
包,可以看到 target
文件夾下生成一個名為 spring-boot-01-helloworld-1.0-SNAPSHOT.jar
的 jar
文件豌鸡,我們可以直接在命令行使用 java -jar xxx.jar
命令進行執(zhí)行嘿般,啟動后在瀏覽器中訪問 http://localhost:8080/hello 可以看到正常返回了 Hello World
。若要結束程序涯冠,關閉命令行窗口即可炉奴。
思考:為什么我們打包后的程序可以直接在命令行使用
java jar
命令就可以部署?
帶著疑問我們來分析一下 spring-boot-01-helloworld-1.0-SNAPSHOT.jar
蛇更,我們使用壓縮文件打開 spring-boot-01-helloworld-1.0-SNAPSHOT.jar
瞻赶,可以看到如下所示的目錄結構:
我們打開 BOOT-INF
文件夾看到有 classes
和 lib
兩個文件夾,我們寫的代碼的二進制字節(jié)碼就在 classes
目錄下派任,而 lib
下可以看到是我們項目依賴的所有 jar
包砸逊,最關鍵的,我們的項目是一個 web
項目掌逛,可以看到所依賴的內嵌的 tomcat
jar包师逸,這是我們項目能獨立部署的關鍵:
其他目錄 META-INF
存放項目的 pom
文件,org
目錄下存放的是 springframework
相關代碼豆混。
5篓像、Hello World 探究
1、POM文件
1皿伺、父項目
依賴路徑入下圖所示:
spring-boot-01-helloworld
的 pom:
<parent>
<artifactId>SpringBoot-In-Action</artifactId>
<groupId>com.demo.springboot</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
它的父項目是 SpringBoot-In-Action
中的 pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<packaging>pom</packaging>
<groupId>com.demo.springboot</groupId>
<artifactId>SpringBoot-In-Action</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>spring-boot-01-helloworld</module>
</modules>
而
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
的父 pom 是 spring-boot-starter-parent-2.2.1.RELEASE.pom
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<artifactId>spring-boot-starter-parent</artifactId>
而它的父 pom 是 spring-boot-dependencies-2.2.1.RELEASE.pom
:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<packaging>pom</packaging>
在這個pom里邊可以看到员辩,它是用來真正管理Spring Boot應用里面的所有依賴版本,定義了每一個依賴的版本鸵鸥;
spring-boot-dependencies-2.x.RELEASE.pom
可以成稱為 Spring Boot的版本仲裁中心
奠滑;
以后我們導入其他依賴默認是不需要寫版本;(當然沒有在dependencies里面管理的依賴自然需要聲明版本號)
2、導入的其他依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web
:我們可以將其拆分為 spring-boot-starter
和 web
兩部分
- spring-boot-starter:spring-boot 場景啟動器养叛;spring-boot-starter-web 幫我們導入了 web 模塊正常運行所依賴的組件种呐。
我們按下 Ctrl
點擊 spring-boot-starter-web 進入 spring-boot-starter-web-2.2.1.RELEASE.pom
,可以看到它導入了很多 web 模塊正常運行需要的相關依賴:
Spring Boot 為我們提供了簡化企業(yè)級開發(fā)的絕大多數(shù)場景的 starter pom(啟動器)弃甥,只要引入了相應場景的 starter pom 爽室,相關技術的絕大部分配置將會消除(即自動配置),從而簡化我們的開發(fā)淆攻。很多業(yè)務場景中我們就會使用到 Spring Boot 為我們自動配置的 bean阔墩,同時 Spring Boot 對這些場景依賴的 jar 也做了嚴格的測試與版本控制,我們可以不必擔心 jar 版本的適配問題瓶珊。
在 Spring Boot 中還有很多這樣的啟動器啸箫,我們打開官方文檔可以看到關于啟動器的描述:
Spring Boot 將所有的功能場景都抽取出來,做成一個個的 starters(啟動器)伞芹,只需要在項目里面引入這些starter 相關場景的所有依賴都會導入進來忘苛。要用什么功能就導入什么場景的啟動器。而我們一般的開發(fā)也是圍繞著這些 starter 來展開唱较。
2扎唾、主程序類(主入口類)
/**
* @SpringBootApplication 來標注一個主程序類,說明這是一個Spring Boot應用南缓,沒有這個注解項目無法啟動
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring應用啟動起來
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
1胸遇、@SpringBootApplication
@SpringBootApplication: Spring Boot應用
標注在某個類上說明這個類是SpringBoot的主配置類,SpringBoot 就運行這個類的 main
方法來啟動 SpringBoot 應用汉形;
進入 @SpringBootApplication
注解內部纸镊,可以看到它實際上是一個復合注解:
@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 {
2、@SpringBootConfiguration
@SpringBootConfiguration:Spring Boot 的配置類概疆;
作用
:標注在某個類上逗威,表示這是一個Spring Boot 的配置類;
進入 @SpringBootConfiguration
內部可以看到届案,它被 Spring 的 @Configuration
注解所注解:
@Configuration
public @interface SpringBootConfiguration {
@Configuration:配置類上來標注這個注解庵楷;配置類 === 配置文件;
進入 @Configuration
內部可以看到楣颠,它被 Spring 的 @Component
注解所注解尽纽;配置類其實也是容器中的一個組件。
@Component
public @interface Configuration {
3童漩、@EnableAutoConfiguration
@EnableAutoConfiguration:開啟自動配置功能
以前在 Spring 中我們需要配置的東西弄贿,現(xiàn)在 Spring Boot 幫我們自動配置;@EnableAutoConfiguration告訴SpringBoot 開啟自動配置功能矫膨,這樣自動配置才能生效差凹;
進入 @EnableAutoConfiguration
內部可以看到下面的代碼:
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自動配置包期奔,將主配置類(@SpringBootApplication
標注的類)的所在包及下面所有子包里面的所有組件掃描到 Spring 容器
進入 @Configuration
內部可以看到它被 @Import
注解所注解。Spring 的底層注解 @Import危尿,給容器中導入一個組件呐萌;導入的組件由 Registrar.class 指定;
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
進入 Registrar 靜態(tài)內部類可以看到如下代碼:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
// 注冊一些 Bean 定義信息谊娇,進行組件的導入工作肺孤;metadata:注解的元信息
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
我們在代碼中打上斷點來看一下:
@Import({AutoConfigurationImportSelector.class}):給容器中導入組件xxx
AutoConfigurationImportSelector:導入哪些組件的選擇器;
我們進入 AutoConfigurationImportSelector
中可以看到如下代碼:
// 將所有需要導入的組件以全類名的方式返回济欢;這些組件就會被添加到容器中
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
將所有需要導入的組件以全類名的方式返回赠堵;這些組件就會被添加到容器中。即AutoConfigurationImportSelector
會給容器中導入非常多的自動配置類(xxxAutoConfiguration)法褥;就是給容器中導入這個場景需要的所有組件茫叭,并配置好這些組件。
我們在代碼中打斷點可以看到如下的結果:
有了自動配置類半等,就免去了我們手動編寫配置注入功能組件等的工作揍愁。
進入上面代碼中的 getCandidateConfigurations
方法,可以看到如下代碼:
// 獲取候選配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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(EnableAutoConfiguration.class, ClassLoader)
方法杀饵,我們在這個進入這個方法可以看下面的代碼:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
// 獲取工廠名
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 用類加載器從類路徑 "META-INF/spring.factories" 中獲取資源
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
// 從獲取的資源中拿出 properties 配置文件吗垮,把獲取的資源當作 properties 配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
// 從 properties 文件中拿到 factoryTypeName
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
所以根據(jù)上面的分析我的得知:Spring Boot 在啟動的時候從類路徑下的 META-INF/spring.factories 中獲取 EnableAutoConfiguration 指定的值,將這些值作為自動配置類導入到容器中凹髓,自動配置類就生效,幫我們進行自動配置工作
怯屉。以前我們在 Spring 中需要自己配置的東西蔚舀,在 Spring Boot 中自動配置類都幫我們配了。
綜上锨络,J2EE 的整體整合解決方案和自動配置都在 spring-boot-autoconfigure-2.2.1.RELEASE.jar (spring-boot-autoconfigure-x.x.x.RELEASE.jar )中:
6赌躺、使用 Spring Initializer 快速創(chuàng)建 Spring Boot項目
1、IDEA:使用 Spring Initializer快速創(chuàng)建項目
所有的 IDE 都支持使用 Spring 的項目創(chuàng)建向導快速創(chuàng)建一個 Spring Boot 項目羡儿,下面我們來看一下如何在 idea 中快速創(chuàng)建一個 Spring Boot 項目礼患。
1、選擇File
→ New
→ Project
或是在一個已經存在的工程中選中工程名然后 New
→ Module
:
2掠归、填寫基本信息 GroupID
缅叠、ArtifactID
3、選擇我們需要依賴的模塊
4虏冻、點擊 Finish
肤粱,接下來向導會聯(lián)網創(chuàng)建 Spring Boot 項目
查看默認生成的 Spring Boot 項目,我們可以看到:
- 主程序已經生成好了厨相,我們只需要寫我們自己的邏輯
-
resources
文件夾中目錄結構:-
static
:保存所有的靜態(tài)資源: js领曼、css鸥鹉、 images等; -
templates
:保存所有的模板頁面(Spring Boot 默認 jar 包使用嵌入式的 Tomcat庶骄,默認不支持 JSP 頁面)毁渗,可以使用模板引擎(freemarker
、thymeleaf
等)单刁; -
application.properties
:Spring Boot 應用的配置文件灸异;可以修改一些默認設置,比如端口等
-
我們在 com.demo.spring.controller
包下新見一個 HelloController
來測試一下我們新建的項目
HelloController 代碼如下:
//這個類的所有方法返回的數(shù)據(jù)直接寫給瀏覽器幻碱,(如果是對象轉為json數(shù)據(jù))
//@ResponseBody
//@Controller
// 上面兩行一般多用在 Spring 項目中
@RestController // 在 Spring Boot 和 Spring4.2.x 之后使用這個來簡化開發(fā)绎狭,返回 RESTAPI 規(guī)范的接口
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello world quick!";
}
}
在瀏覽器中訪問 http://localhost:8080/hello 可以得到下面的返回效果:
2、通過瀏覽器訪問https://start.spring.io/快速創(chuàng)建項目
執(zhí)行完上面的操作后褥傍,瀏覽器會自動下載一個創(chuàng)建好的項目儡嘶,我們使用idea打開即可。
以上恍风,就是我們 Spring Boot 快速入門的全部內容蹦狂,更多詳細內容請查看源代碼了解。