【Java從入門到天黑|06】高品質男性SpringBoot入門及原理(基礎總結版,強烈建議收藏)

2021-08-02 08:00:01

目錄

SpringBoot簡介

Spring是為了解決企業級應用開發的複雜性而建立的,簡化開發。

helloWorld

專案結構分析:

執行原理探究

以後我們匯入依賴預設是不需要寫版本;但是如果匯入的包沒有在依賴中管理著就需要手動設定版本了;

         主啟動類

@EnableAutoConfiguration :開啟自動設定功能

@AutoConfigurationPackage : 自動設定包

@Import({AutoConfigurationImportSelector.class}) :給容器匯入元件 ;

結論:

SpringApplication.run分析

這個類主要做了以下四件事情:

字面量:普通的值 [ 數位,布林值,字串 ]

物件、Map(鍵值對)

陣列( List、set )

修改SpringBoot的預設埠號

注入組態檔

yaml設定注入到實體類完全OK!

測試步驟:

結論:

多環境切換

SpringBoot會從這四個位置全部載入主組態檔;互補設定;

自動設定原理

一句話總結 : 根據當前不同的條件判斷,決定這個設定類是否生效! 一但這個設定類生效;這個設定類就會給容器中新增各種元件;

xxxxAutoConfigurartion:自動設定類;給容器中新增元件xxxxProperties:封裝組態檔中相關屬性;

@Conditional派生註解(Spring註解版原生的@Conditional作用)

那麼多的自動設定類,必須在一定的條件下才能生效;也就是說,我們載入了這麼多的設定類,但不是 所有的都生效了。

我們可以通過啟用   debug=true屬性;來讓控制檯列印自動設定報告,這樣我們就可以很方便的知道哪些自動設定類生效;

Negative matches:(沒有啟動,沒有匹配成功的自動設定類:負匹配) Unconditional classes: (沒有條件的類)

提高:自定義starter

命名規範:


1	#設定專案的存取路徑
2	server.servlet.context-path=/sun

SpringBoot簡介

Spring是一個開源框架,2003 年興起的一個輕量級的Java 開發框架,作者:Rod Johnson  

Spring是為了解決企業級應用開發的複雜性而建立的,簡化開發。

Spring是如何簡化Java開發的?

為了降低Java開發的複雜性,Spring採用了以下4種關鍵策略:

1、基於POJO的輕量級和最小侵入性程式設計,所有東西都是bean

2、通過IOC,依賴注入(DI)和麵向介面實現鬆耦合;

3、基於切面(AOP)和慣例進行宣告式程式設計;

4、通過切面和模版減少樣式程式碼,RedisTemplatexxxTemplate

什麼是SpringBoot?

學過javaweb的同學就知道,開發一個web應用,從最初開始接觸Servlet結合Tomcat, 跑出一個Hello Wolrld程式,是要經歷特別多的步驟; 後來就用了框架Struts,再後來是SpringMVC,到了現在的SpringBoot,過一兩年又會有其他web框架出現;你們有經歷過框架不斷的演進,然後自己開發專案所 有的技術也再不斷的變化、改造嗎?建議都可以去經歷一遍;

言歸正傳,什麼是SpringBoot呢,就是一個javaweb的開發框架,和SpringMVC類似,對比其他javaweb框架的好處,官方說是簡化開發,約定大於設定, you can "just run",能迅速的開發web應用,幾行程式碼開發一個http介面。

所有的技術框架的發展似乎都遵循了一條主線規律:從一個複雜應用場景 衍生 一種規範框架,人們只需要進行各種設定而不需要自己去實現它,這時候強大的設定功能成了優點;發展到一定程度之後,人們 根據實際生產應用情況,選取其中實用功能和設計精華,重構出一些輕量級的框架;之後為了提高開發 效率,嫌棄原先的各類設定過於麻煩,於是開始提倡約定大於設定,進而衍生出一些一站式的解決方   案。

是的這就是Java企業級應用->J2EE->spring->springboot的過程。

隨著 Spring 不斷的發展,涉及的領域越來越多,專案整合開發需要配合各種各樣的檔案,慢慢變得不那麼易用簡單,違背了最初的理念,甚至人稱設定地獄。Spring   Boot   正是在這樣的一個背景下被抽象出來的開發框架,目的為了讓大家更容易的使用 Spring 、更容易的整合各種常用的中介軟體、開源軟體;

Spring Boot 基於 Spring 開發,Spirng Boot 本身並不提供 Spring 框架的核心特性以及擴充套件功能,只是用於快速、敏捷地開發新一代基於 Spring 框架的應用程式。也就是說,它並不是用來替代 Spring 的解決方案,而是和 Spring 框架緊密結合用於提升 Spring 開發者體驗的工具。Spring Boot 約定大於設定的核心思想,預設幫我們進行了很多設定,多數 Spring Boot  應用只需要很少的 Spring  設定。同時它整合了大量常用的第三方庫設定(例如 RedisMongoDBJpaRabbitMQQuartz 等等),Spring Boot 應用中這些第三方庫幾乎可以零設定的開箱即用。

學過javaweb的同學就知道,開發一個web應用,從最初開始接觸Servlet結合Tomcat, 跑出一個Hello Wolrld程式,是要經歷特別多的步驟; 後來就用了框架Struts,再後來是SpringMVC,到了現在的SpringBoot,過一兩年又會有其他web框架出現;你們有經歷過框架不斷的演進,然後自己開發專案所 有的技術也再不斷的變化、改造嗎?建議都可以去經歷一遍;

言歸正傳,什麼是SpringBoot呢,就是一個javaweb的開發框架,和SpringMVC類似,對比其他javaweb框架的好處,官方說是簡化開發,約定大於設定, you can "just run",能迅速的開發web應用,幾行程式碼開發一個http介面。

所有的技術框架的發展似乎都遵循了一條主線規律:從一個複雜應用場景 衍生 一種規範框架,人們只需要進行各種設定而不需要自己去實現它,這時候強大的設定功能成了優點;發展到一定程度之後,人們 根據實際生產應用情況,選取其中實用功能和設計精華,重構出一些輕量級的框架;之後為了提高開發 效率,嫌棄原先的各類設定過於麻煩,於是開始提倡約定大於設定,進而衍生出一些一站式的解決方   案。

是的這就是Java企業級應用->J2EE->spring->springboot的過程。

隨著 Spring 不斷的發展,涉及的領域越來越多,專案整合開發需要配合各種各樣的檔案,慢慢變得不那麼易用簡單,違背了最初的理念,甚至人稱設定地獄。Spring   Boot   正是在這樣的一個背景下被抽象出來的開發框架,目的為了讓大家更容易的使用 Spring 、更容易的整合各種常用的中介軟體、開源軟體;

Spring Boot 基於 Spring 開發,Spirng Boot 本身並不提供 Spring 框架的核心特性以及擴充套件功能,只是用於快速、敏捷地開發新一代基於 Spring 框架的應用程式。也就是說,它並不是用來替代 Spring 的解決方案,而是和 Spring 框架緊密結合用於提升 Spring 開發者體驗的工具。Spring Boot 約定大於設定的核心思想,預設幫我們進行了很多設定,多數 Spring Boot  應用只需要很少的 Spring  設定。同時它整合了大量常用的第三方庫設定(例如 RedisMongoDBJpaRabbitMQQuartz 等等),Spring Boot 應用中這些第三方庫幾乎可以零設定的開箱即用。

Spring Boot的主要優點:

為所有Spring開發者更快的入門

開箱即用,提供各種預設設定來簡化專案設定

內嵌式容器簡化Web專案

沒有冗餘程式碼生成和XML設定的要求

使用 Spring Boot 到底有多爽。晚上試試就知道!

helloWorld

準備工作

我們將學習如何快速的建立一個Spring Boot應用,並且實現一個簡單的Http請求處理。通過這個例子對Spring Boot有一個初步的瞭解,並體驗其結構簡單、開發快速的特性。

我的環境準備:

java version "1.8.0_181" Maven-3.6.1 SpringBoot 2.x 最新版

開發工具: IDEA

建立基礎專案說明:

Spring官方提供了非常方便的工具讓我們快速構建應用 ,   Spring   Initializrhttps://start.spring.io/

專案建立方式一:使用Spring Initializr Web頁面建立專案1、開啟 https://start.spring.io/

2、填寫專案資訊

3、點選」Generate   Project「按鈕生成專案;下載此專案

  4、解壓專案包,並用IDEAMaven專案匯入,一路下一步即可,直到專案匯入完畢。

5、如果是第一次使用,可能速度會比較慢,包比較多、需要耐心等待一切就緒。

專案建立方式二:使用 IDEA 直接建立專案

1、建立一個新專案

2、選擇spring initalizr , 可以看到預設就是去官網的快速構建工具那裡實現

3、填寫專案資訊

4、選擇初始化的元件(初學勾選 Web 即可)

5、填寫專案路徑

6、等待專案構建成功

專案結構分析:

通過上面步驟完成了基礎專案的建立。就會自動生成以下檔案。

1、程式的主啟動類

2、一個 application.properties 組態檔

3、一個 測試類

4、一個 pom.xml

pom.xml 分析

1	<!-- 父依賴 -->
2	<parent>
3	<groupId>org.springframework.boot</groupId>
4	<artifactId>spring-boot-starter-parent</artifactId>
5	<version>2.2.5.RELEASE</version>
6	<relativePath/>
7	</parent>
8	
9	<dependencies>
10	<!-- web場景啟動器 -->
11	<dependency>
12	<groupId>org.springframework.boot</groupId>
13	<artifactId>spring-boot-starter-web</artifactId>
14	</dependency>
15	<!-- springboot單元測試 -->
16	<dependency>
17	<groupId>org.springframework.boot</groupId>
18	<artifactId>spring-boot-starter-test</artifactId>
19	<scope>test</scope>
20	<!-- 剔除依賴 -->
21	<exclusions>
22	<exclusion>
23	<groupId>org.junit.vintage</groupId>
24	<artifactId>junit-vintage-engine</artifactId>
25	</exclusion>
26	</exclusions>
27	</dependency>
28	</dependencies>
29	
30	<build>
31	<plugins>
32	<!-- 打包外掛 -->
33	<plugin>
34	<groupId>org.springframework.boot</groupId>
35	<artifactId>spring-boot-maven-plugin</artifactId>
36	</plugin>
37	</plugins>
38	</build>

編寫HTTP介面

1、在主程式的同級目錄下,新建一個controller包,一定要在同級目錄下,否則識別不到

2、在包中新建一個HelloController

1	@RestController
2	public class HelloController {
3	
4	@RequestMapping("/hello")
5	public String hello() {
6	return "Hello World";
7	}
8	
9	}

3、編寫完畢後,從主程式啟動專案,瀏覽器發起請求,看頁面返回;控制檯輸出了 Tomcat 存取的埠號

簡單幾步,就完成了一個web介面的開發,SpringBoot就是這麼簡單。所以我們常用它來建立我們的微服務專案!

 將專案打成jar包,點選 mavenpackage

如果遇到以上錯誤,可以設定打包時   跳過專案執行測試用例

1	<!--
2	在工作中,很多情況下我們打包是不想執行測試用例的
3	可能是測試用例不完事,或是測試用例會影響資料庫資料
4	跳過測試用例執
5	-->
6	<plugin>
7	<groupId>org.apache.maven.plugins</groupId>
8	<artifactId>maven-surefire-plugin</artifactId>
9	<configuration>
10	<!--跳過專案執行測試用例-->
11	<skipTests>true</skipTests>
12	</configuration>
13	</plugin>

如果打包成功,則會在target目錄下生成一個 jar

打成了jar包後,就可以在任何地方執行了!OK 

如何更改啟動時顯示的字元拼成的字母,SpringBoot呢? 也就是 banner 圖案; 只需一步:到專案下的 resources 目錄下新建一個banner.txt 即可。

圖案可以到:https://www.bootschool.net/ascii 這個網站生成,然後拷貝到檔案中即可!

SpringBoot這麼簡單的東西背後一定有故事,我們之後去進行一波原始碼分析!

執行原理探究

我們之前寫的HelloSpringBoot,到底是怎麼執行的呢,Maven專案,我們一般從pom.xml檔案探究起;

     Pom.xml

父依賴   

其中它主要是依賴一個父專案,主要是管理專案的資源過濾及外掛!

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

 點進去,發現還有一個父依賴

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>

這裡才是真正管理SpringBoot應用裡面所有依賴版本的地方,SpringBoot的版本控制中心;

以後我們匯入依賴預設是不需要寫版本;但是如果匯入的包沒有在依賴中管理著就需要手動設定版本了;

啟動器  spring-boot-starter

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

springboot-boot-starter-xxx:就是spring-boot的場景啟動器

spring-boot-starter-web:幫我們匯入了web模組正常執行所依賴的元件;

SpringBoot將所有的功能場景都抽取出來,做成一個個的starter (啟動器),只需要在專案中引入這些starter即可,所有相關的依賴都會匯入進來 , 我們要用什麼功能就匯入什麼樣的場景啟動器即可 ;我們未來也可以自己自定義 starter

主啟動類

分析完了 pom.xml 來看看這個啟動類

預設的主啟動類

1	//@SpringBootApplication 來標註一個主程式類 , 說明這是一個Spring Boot應用
2	@SpringBootApplication
3	public class SpringbootApplication {
4	
5	public static void main(String[] args) {
6	//以為是啟動了一個方法,沒想到啟動了一個服務
7	SpringApplication.run(SpringbootApplication.class, args);
8	}
9	
10	}

但是一個簡單的啟動類並不簡單!我們來分析一下這些註解都幹了什麼

@SpringBootApplication

作用:標註在某個類上說明這個類是SpringBoot的主設定類 , SpringBoot就應該執行這個類的main方法來啟動SpringBoot應用;

進入這個註解:可以看到上面還有很多其他註解!

@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(
excludeFilters = {@Filter( type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ......
}
v

@ComponentScan

這個註解在Spring中很重要   ,它對應XML設定中的元素。

作用:自動掃描並載入符合條件的元件或者bean   , 將這個bean定義載入到IOC容器中

@SpringBootConfiguration

作用:SpringBoot的設定類 ,標註在某個類上 , 表示這是一個SpringBoot的設定類; 我們繼續進去這個註解檢視

1	// 點進去得到下面的 @Component
2	@Configuration
3	public @interface SpringBootConfiguration {}
4	
5	@Component
6	public @interface Configuration {}

這裡的 @Configuration,說明這是一個設定類 ,設定類就是對應Springxml   組態檔; 裡面的 @Component 這就說明,啟動類本身也是Spring中的一個元件而已,負責啟動應用! 我們回到 SpringBootApplication 註解中繼續看

@EnableAutoConfiguration

@EnableAutoConfiguration :開啟自動設定功能

以前我們需要自己設定的東西,而現在SpringBoot可以自動幫我們設定    ;    @EnableAutoConfiguration

告訴SpringBoot開啟自動設定功能,這樣自動設定才能生效;

點進註解接續檢視:

@AutoConfigurationPackage : 自動設定包

1	@Import({Registrar.class})
2	public @interface AutoConfigurationPackage {
3	}

@import Spring底層註解@import , 給容器中匯入一個元件

Registrar.class 作用:將主啟動類的所在包及包下面所有子包裡面的所有元件掃描到Spring容器 ; 這個分析完了,退到上一步,繼續看

@Import({AutoConfigurationImportSelector.class}) :給容器匯入元件 ;

AutoConfigurationImportSelector : 自動設定匯入選擇器,那麼它會匯入哪些元件的選擇器呢? 我們點選去這個類看原始碼:

1、這個類中有一個這樣的方法

// 獲得候選的設定
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//這裡的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我們最開始看的啟動自動匯入組態檔的註解類;EnableAutoConfiguration List<String> configurations =
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryCl ass(), 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;
}

2、這個方法又呼叫了    SpringFactoriesLoader 類的靜態方法!我們進入SpringFactoriesLoader類loadFactoryNames() 方法

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
//這裡它又呼叫了 loadSpringFactories 方法
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

3、我們繼續點選檢視 loadSpringFactories 方法

1	private static Map<String, List<String>> loadSpringFactories(@Nullable
	ClassLoader classLoader) {
2	//獲得classLoader , 我們返回可以看到這裡得到的就是EnableAutoConfiguration標註
	的類本身
3	MultiValueMap<String, String> result =
	(MultiValueMap)cache.get(classLoader);
4	if (result != null) {
5	return result;
6	} else {
7	try {
8	//去獲取一個資源 "META-INF/spring.factories"
9	Enumeration<URL> urls = classLoader != null ?
	classLoader.getResources("META-INF/spring.factories") :
	ClassLoader.getSystemResources("META-INF/spring.factories");
10	LinkedMultiValueMap result = new LinkedMultiValueMap();
11	
12	//將讀取到的資源遍歷,封裝成為一個Properties
13	while(urls.hasMoreElements()) {
14	URL url = (URL)urls.nextElement();
15	UrlResource resource = new UrlResource(url);
16	Properties properties =
	PropertiesLoaderUtils.loadProperties(resource);
17	Iterator var6 = properties.entrySet().iterator();
18	
19	while(var6.hasNext()) {
20	Entry<?, ?> entry = (Entry)var6.next();
21	String factoryClassName =
	((String)entry.getKey()).trim();
22	String[] var9 =
	StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
23	int var10 = var9.length;
24	
25	for(int var11 = 0; var11 < var10; ++var11) {
26	String factoryName = var9[var11];
27	result.add(factoryClassName, factoryName.trim());
28	}
29	}
30	}
31	
32	cache.put(classLoader, result);
33	return result;
34	} catch (IOException var13) {
35	throw new IllegalArgumentException("Unable to load factories
	from location [META-INF/spring.factories]", var13);
36	}
37	}
38	}

4、發現一個多次出現的檔案spring.factories,全域性搜尋

我們根據源頭開啟spring.factories   ,   看到了很多自動設定的檔案;這就是自動設定根源所在!

WebMvcAutoConfiguration

我們在上面的自動設定類隨便找一個開啟看看,比如   :   WebMvcAutoConfiguration

可以看到這些一個個的都是JavaConfig設定類,而且都注入了一些Bean,可以找一些自己認識的類,看 著熟悉一下!

所以,自動設定真正實現是從classpath中搜尋所有的META-INF/spring.factories組態檔    ,並將其中對應的 org.springframework.boot.autoconfigure. 包下的設定項,通過反射範例化為對應標註了@ConfigurationJavaConfig形式的IOC容器設定類 , 然後將這些都彙總成為一個範例並載入到IOC容器中。

結論:

  1. SpringBoot在啟動的時候從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值
  2. 將這些值作為自動設定類匯入容器 , 自動設定類就生效 , 幫我們進行自動設定工作;
  3. 整個J2EE的整體解決方案和自動設定都在springboot-autoconfigurejar包中;
  4. 它會給容器中匯入非常多的自動設定類 xxxAutoConfiguration, 就是給容器中匯入這個場景需要的所有元件 , 並設定好這些元件 ;
  5. 有了自動設定類 , 免去了我們手動編寫設定注入功能元件等的工作;

現在大家應該大概的瞭解了下,SpringBoot的執行原理,後面我們還會深化一次!

SpringApplication

我最初以為就是執行了一個main方法,沒想到卻開啟了一個服務;

@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args);
}
}

 

SpringApplication.run分析

分析該方法主要分兩部分,一部分是SpringApplication的範例化,二是run方法的執行

SpringApplication

這個類主要做了以下四件事情:

1、推斷應用的型別是普通的專案還是Web專案

2、查詢並載入所有可用初始化器 , 設定到initializers屬性中

3、找出所有的應用程式監聽器,設定到listeners屬性中 4、推斷並設定main方法的定義類,找到執行的主類

檢視構造器:

1	public SpringApplication(ResourceLoader resourceLoader, Class...
	primarySources) {
2	// ......
3	this.webApplicationType = WebApplicationType.deduceFromClasspath();
4	this.setInitializers(this.getSpringFactoriesInstances();
5	
	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class
	));
6	this.mainApplicationClass = this.deduceMainApplicationClass();
7	}

 run方法

Yaml語法學習

組態檔

SpringBoot使用一個全域性的組態檔 , 組態檔名稱是固定的

application.properties

語法結構 : key=value application.yml

語法結構 :key:空格 value

組態檔的作用   :修改SpringBoot自動設定的預設值,因為SpringBoot在底層都給我們自動設定好了;

比如我們可以在組態檔中修改Tomcat    預設啟動的埠號!測試一下!

 server.port=8081

yaml 概述

YAML"YAML Ain't a Markup Language" YAML不是一種標示語言)的遞迴縮寫。

在開發的這種語言時,YAML 的意思其實是:"Yet Another Markup Language"(仍是一種標示語言)

這種語言以資料做為中心,而不是以標示語言為重點!
以前的組態檔,大多數都是使用xml來設定;比如一個簡單的埠設定,我們來對比下yamlxml 傳統xml設定:

<server>

<port>8081<port>

</server>

yaml設定

serverprot: 8080

yml基礎語法

說明:語法要求嚴格!

1、空格不能省略

2、以縮排來控制層級關係,只要是左邊對齊的一列資料都是同一個層級的。

3、屬性和值的大小寫都是十分敏感的。

字面量:普通的值 [ 數位,布林值,字串 ]

字面量直接寫在後面就可以 , 字串預設不用加上雙引號或者單引號;

k: v

注意:

「 」 雙引號,不會跳脫字串裡面的特殊字元 , 特殊字元會作為本身想表示的意思; 比如 : name: "kuang \n shen" 輸出 : kuang 換行 shen

'' 單引號,會跳脫特殊字元 , 特殊字元最終會變成和普通字元一樣輸出

比如 : name: ‘kuang \n shen’   輸出 : kuang  \n   shen

物件、Map(鍵值對)

#物件、Map格式

k:

v1:

v2:

在下一行來寫物件的屬性和值得關係,注意縮排;比如:

student:

name: sunjiaoshou

age: 3

行內寫法

student: {name: sunjiaoshou,age: 3}

陣列( Listset

- 值表示陣列中的一個元素,比如:

pets:

  1. cat
  2. dog
  3. pig

行內寫法

pets: [cat,dog,pig]

修改SpringBoot的預設埠號

組態檔中新增,埠號的引數,就可以切換埠;

server:

port: 8082

注入組態檔


yaml檔案更強大的地方在於,他可以給我們的實體類直接注入匹配值!

Yaml注入組態檔

1、在springboot專案中的resources目錄下新建一個檔案 application.yml

2、編寫一個實體類 Dog

1	package com.kuang.springboot.pojo;
2	
3	@Component //註冊bean到容器中
4	public class Dog {
5	private String name;
6	private Integer age;
7	
8	//有參無參構造、get、set方法、toString()方法
9	}

3、思考,我們原來是如何給bean注入屬性值的!   @Value,給狗狗類測試一下

@Component //註冊bean public class Dog {
@Value("阿黃") private String name; @Value("18")
private Integer age;
}

4、在SpringBoot的測試類下注入狗狗輸出一下;

1	@SpringBootTest
2	class DemoApplicationTests {
3	
4	@Autowired //將狗狗自動注入進來
5	Dog dog;
6	
7	@Test
8	public void contextLoads() {
9	System.out.println(dog); //列印看下狗狗物件
10	}
11	
12	}

結果成功輸出,@Value注入成功,這是我們原來的辦法對吧

5、我們在編寫一個複雜一點的實體類:Person  

1	@Component //註冊bean到容器中
2	public class Person {
3	private String name;
4	private Integer age;
5	private Boolean happy;
6	private Date birth;
7	private Map<String,Object> maps;
8	private List<Object> lists;
9	private Dog dog;
10	
11	//有參無參構造、get、set方法、toString()方法
12	}

6、我們來使用yaml設定的方式進行注入,大家寫的時候注意區別和優勢,我們編寫一個yaml設定

person:
name: qinjiang age: 3
happy: false birth: 2000/01/01
maps: {k1: v1,k2: v2} lists:
-	code
-	girl
-	music dog:
name: 旺財
age: 1

7、我們剛才已經把person這個物件的所有值都寫好了,我們現在來注入到我們的類中!

/*
@ConfigurationProperties作用:
將組態檔中設定的每一個屬性的值,對映到這個元件中;
告訴SpringBoot將本類中的所有屬性和組態檔中相關的設定進行繫結
引數 prefix = 「person」 : 將組態檔中的person下面的所有屬性一一對應
*/
@Component //註冊bean @ConfigurationProperties(prefix = "person") public class Person {
private String name; private Integer age; private Boolean happy; private Date birth;
private Map<String,Object> maps; private List<Object> lists; private Dog dog;
}

8IDEA 提示,springboot設定註解處理器沒有找到,讓我們看檔案,我們可以檢視檔案,找到一個依賴

 

<!-- 匯入組態檔處理器,組態檔進行繫結就會有提示,需要重新啟動 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

 9、確認以上設定都OK之後,我們去測試類中測試一下

1	@SpringBootTest
2	class DemoApplicationTests {
3	
4	@Autowired
5	Person person; //將person自動注入進來
6	
7	@Test
8	public void contextLoads() {
9	System.out.println(person); //列印person資訊
10	}
11	
12	}


結果:所有值全部注入成功!

yaml設定注入到實體類完全OK

課堂測試:

1、將組態檔的key 值 和 屬性的值設定為不一樣,則結果輸出為null,注入失敗

2、在設定一個person2,然後將 @ConfigurationProperties(prefix = "person2") 指向我們的

person2

載入指定組態檔

@PropertySource 載入指定的組態檔; @configurationProperties:預設從全域性組態檔中獲取值; 1、我們去在resources目錄下新建一個person.properties檔案

name=sunjiaoshou

2、然後在我們的程式碼中指定載入person.properties檔案

1	@PropertySource(value = "classpath:person.properties")
2	@Component //註冊bean
3	public class Person {
4	
5	@Value("${name}")
6	private String name;
7	
8	......
9	}

3、再次輸出測試一下:指定組態檔繫結成功!

組態檔預留位置

person:
name: sunjiaoshou${random.uuid} # 隨機uuid age: ${random.int} # 隨機int
happy: false birth: 2000/01/01
maps: {k1: v1,k2: v2} lists:
-	code
-	girl
-	music dog:
# 參照person.hello 的值,如果不存在就用 :後面的值,即 other,然後拼接上_旺財
name: ${person.hello:other}_旺財age: 1

 回顧properties設定

我們上面採用的yaml方法都是最簡單的方式,開發中最常用的;也是springboot所推薦的!那我們來嘮   嘮其他的實現方式,道理都是相同得;寫還是那樣寫;組態檔除了yml還有我們之前常用的properties

, 我們沒有講,我們來嘮嘮!

【注意】properties組態檔在寫中文的時候,會有亂碼   ,   我們需要去IDEA中設定編碼格式為UTF-8

settings-->FileEncodings 中設定;

測試步驟:

1、新建一個實體類User

@Component //註冊bean public class User {
private String name; private int age; private String sex;
}

  2、編輯組態檔 user.properties

1	user1.name=sunjiaoshou
2	user1.age=18
3	user1.sex=男

 3、我們在User類上使用@Value來進行注入!

@Component //註冊bean
@PropertySource(value = "classpath:user.properties") public class User {
//直接使用@value
@Value("${user.name}") //從組態檔中取值private String name;
@Value("#{9*2}") // #{SPEL} Spring表示式private int age;
@Value("男") // 字面量
private String sex;
}

4Springboot測試

1	@SpringBootTest
2	class DemoApplicationTests {
3	
4	@Autowired
5	User user;
6	
7	@Test
8	public void contextLoads() {
9	System.out.println(user);
10	}
11	
12	}

結果正常輸出

對比小結

@Value這個使用起來並不友好!我們需要為每個屬性單獨註解賦值,比較麻煩;我們來看個功能對比圖

 

1@ConfigurationProperties只需要寫一次即可 , @Value則需要每個欄位都新增

2、鬆散繫結:這個什麼意思呢? 比如我的yml中寫的last-name,這個和lastName是一樣的, - 後面跟著的字母預設是大寫的。這就是鬆散繫結。可以測試一下

3JSR303資料校驗 , 這個就是我們可以在欄位是增加一層過濾器驗證 , 可以保證資料的合法性

4、複雜型別封裝,yml中可以封裝物件 , 使用value就不支援

結論:

設定yml和設定properties都可以獲取到值 , 強烈推薦 yml

如果我們在某個業務中,只需要獲取組態檔中的某個值,可以使用一下 @value; 如果說,我們專門編寫了一個JavaBean來和組態檔進行一一對映,就直接

@configurationProperties,不要猶豫!

SR303資料校驗

Springboot中可以用@validated來校驗資料,如果資料異常則會統一丟擲異常,方便異常中心統一處 理。我們這裡來寫個註解讓我們的name只能支援Email格式

1	@Component //註冊bean
2	@ConfigurationProperties(prefix = "person")
3	@Validated //資料校驗
4	public class Person {
5	
6	@Email(message="郵箱格式錯誤") //name必須是郵箱格式
7	private String name;
8	}

 執行結果 :   default message [不是一個合法的電子郵件地址]

使用資料校驗,可以保證資料的正確性;   下面列出一些常見的使用

1	@NotNull(message="名字不能為空")
2	private String userName;
3	@Max(value=120,message="年齡最大不能查過120")
4	private int age;
5	@Email(message="郵箱格式錯誤")
6	private String email;
7	
8	空檢查
9	@Null	驗證物件是否為null
10	@NotNull	驗證物件是否不為null, 無法查檢長度為0的字串
11	@NotBlank	檢查約束字串是不是Null還有被Trim的長度是否大於0,只對字串,且會去掉前後空
	格.
12	@NotEmpty	檢查約束元素是否為NULL或者是EMPTY.
13	
14	Booelan檢查
15	@AssertTrue	驗證 Boolean 物件是否為 true
16	@AssertFalse	驗證 Boolean 物件是否為 false
17	
18	長度檢查
19	@Size(min=, max=) 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內

20	
@Length(min=, max=) string is between min and max included.
21	
22	日期檢查
23	@Past	驗證 Date 和 Calendar 物件是否在當前時間之前
24	@Future	驗證 Date 和 Calendar 物件是否在當前時間之後
25	@Pattern	驗證 String 物件是否符合正規表示式的規則
26	
27	.......等等
28	除此以外,我們還可以自定義一些資料校驗規則

多環境切換

profileSpring對不同環境提供不同設定功能的支援,可以通過啟用不同的環境版本,實現快速切換環境;

多組態檔

我們在主組態檔編寫的時候,檔名可以是 application-{profile}.properties/yml ,   用來指定多個環境版本;

例如:application-test.properties 代表測試環境設定  

application-dev.properties 代表開發環境設定但是Springboot並不會直接啟動這些組態檔,它預設使用application.properties主組態檔

我們需要通過一個設定來選擇需要啟用的環境:

1	#比如在組態檔中指定使用dev環境,我們可以通過設定不同的埠號進行測試;
2	#我們啟動SpringBoot,就可以看到已經切換到dev下的設定了;
3	spring.profiles.active=dev

yml的多檔案塊

properties組態檔中一樣,但是使用yml去實現不需要建立多個組態檔,更加方便了

server: port: 8081
#選擇要啟用那個環境塊
spring: profiles:
active: prod
server:
port: 8083
spring:
profiles: dev #設定環境的名稱
server:
port: 8084
spring:
profiles: prod #設定環境的名稱

注意:如果ymlproperties同時都設定了埠,並且沒有啟用其他環境 , 預設會使用properties組態檔的

組態檔載入位置

外部載入組態檔的方式十分多,我們選擇最常用的即可,在開發的資原始檔中進行設定!

springboot 啟動會掃描以下位置的application.properties或者application.yml檔案作為Spring boot預設組態檔

1	優先順序1:專案路徑下的config資料夾組態檔
2	優先順序2:專案路徑下組態檔
3	優先順序3:資源路徑下的config資料夾組態檔
4	優先順序4:資源路徑下組態檔

優先順序由高到底,高優先順序的設定會覆蓋低優先順序的設定;

SpringBoot會從這四個位置全部載入主組態檔;互補設定;

我們在最低階的組態檔中設定一個專案存取路徑的設定來測試互補問題

1	#設定專案的存取路徑
2	server.servlet.context-path=/sun

擴充套件:指定位置載入組態檔

我們還可以通過spring.config.location來改變預設的組態檔位置

專案打包好以後,我們可以使用命令列引數的形式,啟動專案的時候來指定組態檔的新位置;這種情況,一般是後期運維做的多,相同設定,外部指定的組態檔優先順序最高

java -jar spring-boot-config.jar --
spring.config.location=F:/application.properties

自動設定原理

組態檔到底能寫什麼?怎麼寫?

我們以HttpEncodingAutoConfigurationHttp編碼自動設定)為例解釋自動設定原理;

1	//表示這是一個設定類,和以前編寫的組態檔一樣,也可以給容器中新增元件;
2	@Configuration
3	
4	//啟動指定類的ConfigurationProperties功能;
5	//進入這個HttpProperties檢視,將組態檔中對應的值和HttpProperties繫結起來;
6	//並把HttpProperties加入到ioc容器中
7	@EnableConfigurationProperties({HttpProperties.class})
8	
9	//Spring底層@Conditional註解
10	//根據不同的條件判斷,如果滿足指定的條件,整個設定類裡面的設定就會生效;
11	//這裡的意思就是判斷當前應用是否是web應用,如果是,當前設定類生效
12	@ConditionalOnWebApplication(
13	type = Type.SERVLET
14	)
15	
16	//判斷當前專案有沒有這個類CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
17	@ConditionalOnClass({CharacterEncodingFilter.class})
18	
19	//判斷組態檔中是否存在某個設定:spring.http.encoding.enabled;
20	//如果不存在,判斷也是成立的
21	//即使我們組態檔中不設定pring.http.encoding.enabled=true,也是預設生效的;
22	@ConditionalOnProperty(
23	prefix = "spring.http.encoding",
24	value = {"enabled"},
25	matchIfMissing = true
26	)
27	
28	public class HttpEncodingAutoConfiguration {
29	//他已經和SpringBoot的組態檔對映了
30	private final Encoding properties;
31	//只有一個有參構造器的情況下,引數的值就會從容器中拿
32	public HttpEncodingAutoConfiguration(HttpProperties properties) {
33	this.properties = properties.getEncoding();
34	}
35	
36	//給容器中新增一個元件,這個元件的某些值需要從properties中獲取
37	@Bean
38	@ConditionalOnMissingBean //判斷容器沒有這個元件?
39	public CharacterEncodingFilter characterEncodingFilter() {
40	CharacterEncodingFilter filter = new
	OrderedCharacterEncodingFilter();
41	filter.setEncoding(this.properties.getCharset().name());
	filter.setForceRequestEncoding(this.properties.shouldForce(org.springframew
	ork.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
43	
	filter.setForceResponseEncoding(this.properties.shouldForce(org.springframe
	work.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
44	return filter;
45	}
46	//。。。。。。。
47	}

一句話總結 : 根據當前不同的條件判斷,決定這個設定類是否生效! 一但這個設定類生效;這個設定類就會給容器中新增各種元件;

這些元件的屬性是從對應的properties類中獲取的,這些類裡面的每一個屬性又是和組態檔繫結 的; 所有在組態檔中能設定的屬性都是在xxxxProperties類中封裝著; 組態檔能設定什麼就可以參照某個功能對應的這個屬性類

/從組態檔中獲取指定的值和bean的屬性進行繫結@ConfigurationProperties(prefix = "spring.http") public class HttpProperties {
// .....
}

我們去組態檔裡面試試字首,看提示!

這就是自動裝配的原理!

1SpringBoot啟動會載入大量的自動設定類

2、我們看我們需要的功能有沒有在SpringBoot預設寫好的自動設定類當中;

3、我們再來看這個自動設定類中到底設定了哪些元件;(只要我們要用的元件存在在其中,我們就不需 要再手動設定了)

4、給容器中自動設定類新增元件的時候,會從properties類中獲取某些屬性。我們只需要在組態檔中 指定這些屬性的值即可;

xxxxAutoConfigurartion:自動設定類;給容器中新增元件xxxxProperties:封裝組態檔中相關屬性;

瞭解:@Conditional

瞭解完自動裝配的原理後,我們來關注一個細節問題,自動設定類必須在一定的條件下才能生效;

@Conditional派生註解(Spring註解版原生的@Conditional作用)

作用:必須是@Conditional指定的條件成立,才給容器中新增元件,設定配裡面的所有內容才生效

 

那麼多的自動設定類,必須在一定的條件下才能生效;也就是說,我們載入了這麼多的設定類,但不是 所有的都生效了。

我們怎麼知道哪些自動設定類生效?

我們可以通過啟用   debug=true屬性;來讓控制檯列印自動設定報告,這樣我們就可以很方便的知道哪些自動設定類生效;

 

1	#開啟springboot的偵錯類
2	debug=true

Positive matches:(自動設定類啟用的:正匹配)

Negative matches:(沒有啟動,沒有匹配成功的自動設定類:負匹配) Unconditional classes: (沒有條件的類)

【演示:檢視輸出的紀錄檔】

掌握吸收理解原理,即可以不變應萬變!

提高:自定義starter

我們分析完畢了原始碼以及自動裝配的過程,我們可以嘗試自定義一個啟動器來玩玩

啟動器模組是一個 空 jar 檔案,僅提供輔助性依賴管理,這些依賴可能用於自動裝配或者其他類庫;

命名歸約:

官方命名:

字首:  spring-boot-starter-xxx

比如:spring-boot-starter-web....

自定義命名:

xxx-spring-boot-starter

比如:mybatis-spring-boot-starter

編寫啟動器

1、在IDEA中新建一個空專案 spring-boot-starter-diy


2、新建一個普通Maven模組:kuang-spring-boot-starter

3、新建一個Springboot模組:kuang-spring-boot-starter-autoconfigure

 

4、點選apply即可,基本結構

 

5、在我們的 starter 中 匯入 autoconfigure 的依賴!

<!-- 啟動器 -->
<dependencies>
<!-- 引入自動設定模組 -->
<dependency>
<groupId>com.sunjiaoshou</groupId>
<artifactId>kuang-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>

 6、將 autoconfigure 專案下多餘的檔案都刪掉,Pom中只留下一個 starter,這是所有的啟動器基本配

 7、我們編寫一個自己的服務

public class HelloService {


HelloProperties helloProperties;


public HelloProperties getHelloProperties() { return helloProperties;
}


public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties;
}
public String sayHello(String name){
return helloProperties.getPrefix() + name +
helloProperties.getSuffix();
}

}

8、編寫HelloProperties 設定類

1	package com.sunjiaoshou;
2	
3	import org.springframework.boot.context.properties.ConfigurationProperties;
4	
5	// 字首 kuang.hello
6	@ConfigurationProperties(prefix = "kuang.hello")
7	public class HelloProperties {
8	
9	private String prefix;
10	private String suffix;
11	
12	public String getPrefix() {
13	return prefix;
14	}
15	
16	public void setPrefix(String prefix) {
17	this.prefix = prefix;
18	}
19	
20	public String getSuffix() {
21	return suffix;
22	}
23	
24	public void setSuffix(String suffix) {
25	this.suffix = suffix;
26	}
27	}

9、編寫我們的自動設定類並注入bean,測試!

1	package com.sunjiaoshou;
2	
3	import org.springframework.beans.factory.annotation.Autowired;
4	import
	org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
	;
5	import
	org.springframework.boot.context.properties.EnableConfigurationProperties;
6	import org.springframework.context.annotation.Bean;
7	import org.springframework.context.annotation.Configuration;
8	
9	@Configuration
10	@ConditionalOnWebApplication //web應用生效
11	@EnableConfigurationProperties(HelloProperties.class)
12	public class HelloServiceAutoConfiguration {
13	
14	@Autowired
15	HelloProperties helloProperties;
17		@Bean
18		public HelloService helloService(){
19		HelloService service = new HelloService();
20		service.setHelloProperties(helloProperties);
21		return service;
22		}
23		
24	}	

10、在resources編寫一個自己meta-info\spring.factories

1	# Auto Configure
2	org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
3	com.kuang.HelloServiceAutoConfiguration

MMM11、編寫完成後,可以安裝到maven倉庫中!

ET

新建專案測試我們自己的寫的啟動器

1、新建一個SpringBoot 專案

2、匯入我們自己寫的啟動器

<dependency>
<groupId>com.kuang</groupId>
<artifactId>kuang-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

 3、編寫一個 HelloController 進行測試我們自己的寫的介面!

package com.sunjiaoshou.controller;


@RestController
public class HelloController {


@Autowired
	


}	HelloService helloService;

@RequestMapping("/hello") public String hello(){
return helloService.sayHello("zxc");
}

A-I4、編寫組態檔 application.properties

1	sunjiaoshou.hello.prefix="ppp"
2	sunjiaoshou.hello.suffix="sss"

NF\spring.factoriesETA-INF\spring.factoriesETA-INF\spring.factories

5、啟動專案進行測試,結果成功 !

 

孫叫獸溫馨提示:學完的東西一定要多下去實踐! 才有可能成為高品質男性!