1. 程式人生 > >《Spring + Cloud微服務實戰》讀書筆記(二)————Spring Boot

《Spring + Cloud微服務實戰》讀書筆記(二)————Spring Boot

1.Spring Boot簡介

1.1簡化配置

通過設計大量的自動化配置等方式來簡化Spring原有樣板化的配置,使得開發者可以快速構建應用。

1.2簡化依賴管理

Spring Boot 通過一系列Starter POMs的定義,讓我們整合各項功能的時候,不需要再Maven的pom.xml中
維護那些錯中複雜的依賴關係,而是通過類似模組化的Starter模組定義來引用,使得依賴管理工作變得更為簡單。

1.3簡化部署

在如今容器化大行其道的時代,Spring Boot除了可以很好融入Docker之外,其自身就支援嵌入式大的Tomcat、Jetty等容器。
所以,通過 Spring Boot 構建的應用不再需要安裝Tomcat,只需要將Spring Boot應用打成jar包,並通過
java -jar 命令直接執行就能啟動一個標準化的Web應用,這使得Spring Boot應用變得非常輕便。

1.4優化開發環節

整個Spring Boot的生態系統都使用到了Groovy,可以通過使用Gradle和Groovy來開發Spring Boot應用。

@RestController
public class HelloController {

@RequestMapping("/hello")
public String index(){
    return "Hello World";
}

}
這段程式碼編譯打包後,使用 java -jar 命令就能啟動一個煩惱會“hello World”的RESTful API。

2.快速入門

2.1構建Maven專案

訪問

http://start.spring.io/ ,該頁面提供了以Maven 或 Gradle構建Spring Boot 專案的功能。
這裡寫圖片描述

將下載的壓縮包,解壓,匯入到Eclipse.

2.2目錄介紹

src/main/java: 程式碼目錄
src/main/resources:配置目錄。
該目錄用來存放應用的一些配置資訊,比如應用名,服務埠,資料庫連結等。
該目錄還有 static目錄和templates目錄。
static : 存放靜態資源,如圖片、CSS、JavaScript等。
templates:存放Web頁面的模板檔案
src/test/:單元測試目錄。
通過JUnit 4實現測試類,可以直接用執行Spring Boot應用的測試。

2.3 Maven配置

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.study</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot</name>
    <description>Demo project for Spring Boot</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <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>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

父專案中定義了Spring Boot版本的基礎依賴以及一些預設配置內容,比如,配置檔案 application.properties的位置等。

專案依賴dependencies配置中,包含了:

  • spring-boot-starter-web: 全棧Web開發模組,包含嵌入式Tomcat、Spring MVC.

  • spring-boot-starter-test:通用測試模組,包含JUnit,Hamcrest,Mockito.

    這裡引入的web和test模組,在Spring Boot生態中被稱為Starter POMs.
    Starter POMs是一系列輕便的依賴包,是一套一站式的Spring相關技術的解決方案。

    開發Web應用的時候,引入spring-boot-starter-web。
    需要訪問資料庫能力時,再引入spring-boot-starter-jdbc 或spring-boot-starter-data-jpa.

在使用Spring Boot構建應用的時候,各項功能木塊的整合不再需要在pom.xml中做的大量的依賴配置,
而是通過使用 Starter POMs定義的依賴包,使得模組整合變得非常輕巧,易於理解與使用。

2.3 構建和啟動

專案構建的build部分,引入了Spring Boot的Maven外掛,該外掛可以幫助我們方便地啟停應用,
這樣在開發時就不用每次去找主類或是打包成jar來執行微服務。
只需要通過 mvn spring-boot:run 命令就可以快速啟動Spring Boot應用。

在伺服器上部署執行時,通常先使用 mvn install 將應用打包成jar包,在通過 java -jar xxx.jar來啟動應用

2.4編寫單元測試

功能實現之後,要隨手寫配套單元測試的習慣,這在微服務架構中尤為重要。
在src/test/下寫測試類:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes=HelloController.class)
    @WebAppConfiguration
    public class HelloApplicationTests {

    private MockMvc mvc;

    @Before
    public void setUp()  throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
    }

    @Test
    public void hello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andExpect(content().string(equalTo("Hello World")));
    }
}

程式碼解析:

  • @RunWith(SpringJUnit4ClassRunner.class) 引入Spring 對 JUnit4 的支援
  • @SpringBootTest(classes=HelloController.class) 指定Spring Boot的啟動類
  • @WebAppConfiguration 開啟Web應用的配置,用於模擬ServletContext
  • MockMvc 物件:
    用於模擬呼叫Controller的介面發起請求。
    • perform函式執行一次請求呼叫
    • accept用於執行接收的資料型別
    • andExpect用於判斷介面返回的期望值
  • @Before 初始化對HelloController的模擬
    靜態引入,讓status、content、equalTo函式可用:
    import static org.hamcrest.Matchers.equalTo;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

2.5配置檔案

Spring Boot 的預設配置檔案位置為src/main/resources/application.properties
關於Spring Boot應用的配置內容都可以集中在該檔案中,根據我們引入的不同Starter模組,
可以在這裡定義容器埠號、資料庫連線資訊、日誌級別等各種配置資訊。
如:

  • 自定義Web模組的服務埠號:
    server.port=8888
  • 指定應用名:
    spring.application.name=hello

Spring Boot的配置檔案除了可以使用傳統的properties檔案之外,還支援YAML檔案。
YAML採用的配置格式是以類似大綱的縮排形式來表示:

environments:
        dev:
            url: http://dev.bar.com
            name: Developer Setup
        prod:
            url: http://foo.bar.com
            name: My Cool App

通過YAML的配置方式,利用階梯化縮排方式,其結構更為清晰易讀,同時配置內容的字元量也顯著減少。
另外,YAML還可以在一個單個檔案中通過使用spring.profiles屬性來定義多個額不用的環境配置。

server:
    port:8881
---
spring:
    profiles:test
server:
    port:8882
---
spring:
    profiles:prod
server:
    port:8883

通過上面的配置,如果指定為test環境時,server.port將使用8882埠;
而在prod環境中,server.port將使用8883埠;
如果沒有指定環境,server.port將使用8881埠。

注意

  1. YAML目前無法通過@PropertySource註解來載入配置
  2. YAML將屬性載入到記憶體中儲存的時候是有序的,所以當配置檔案中的資訊需要具體順序含義時,應選擇YAML

    2.5.1自定義引數

    可以在配置檔案中定義一些我們需要的自定義屬性。

book.name=SpringBook
book.author=spring

在應用中可以通過@Value註解來載入這些自定義引數:

@Component
public class Book {
    @Value("${book.name}")
    private String name;
    @Value("${book.author}")
    private String author;
}

@Value註解載入屬性值的時候可以支援兩種表示式:

  • 一種是上面的PlaceHolder方式,格式為${…},大括號內為PlaceHolder
  • 另一種是使用SpEL表示式(Spring Expression Language),格式為#{…},大括號內為SpEL表示式

2.5.2引數引用

在application.properties中國的各個引數之間可以直接通過使用PlaceHolder的方式來進行引用:

book.name=SpringBook
book.author=spring
book.desc=${book.author} is writing 《${book.name}》

2.5.3使用隨機數

在一些特殊情況下,需要有些引數每次被載入的時候不是一個固定的值,如金鑰、服務埠等。
在Spring Boot的屬性配置檔案中,可以通過使用${random}配置來產生隨機的int值、long值或者String字串。

${random}的配置方式使用:

# 隨機字串
com.randomString.value=${random.value}
# 隨機 int
com.randomInt.value=${random.int}
# 隨機 long
com.randomLong.value=${random.long}
#10 以內的隨機數
com.randomInt.test1=${random.int(10)}
#10~20 的隨機數
com.randomInt.test2=${random.int[10,20]}

2.5.4命令列引數

Spring Boot應用,可以使用命令 java -jar 來啟動的方式,該命令還可以指定應用引數,如:
java -jar xxx.jar –server.port=8888

在用命令列方式啟動Spring Boot 應用時,使用“–”符號,就是對application.properties中的屬性值進行賦值的標識。

通過命令列來修改屬性值是 Spring Boot 非常重要的一個特性。
通過此特性,理論上已經使得應用的屬性在啟動前是可變得,所以埠號、資料庫連線等,都是可以在應用啟動時發生改變的。

2.5.5多環境配置

對於多環境的配置,各種專案構建工具或是框架的基本思路是一致的,通過配置多份不同環境的配置檔案,
再通過打包命令指定需要打包的內容之後進行區分打包。

在Spring Boot中,多環境配置的檔名需要滿足 application-{profile}.properties的格式,其中
{profile}對應環境標識,如:

  • application-dev.properties 開發環境
  • application-test.properties 測試環境
  • application-prod.properties 生產環境

至於具體哪個配置檔案會被載入,需要在 application.properties 檔案中通過
spring.profiles.active 屬性來設定,其值對應配置檔案中的{profile}值。

如spring.profiles.active=test就會載入 application-test.properties配置檔案內容。

2.5.6載入順序

不同環境配置的修改不得不去獲取工程內容來修改這些配置內容,當應用非常多的時候就會變得非常不方便。
同時,配置內容對開發人員都可見,這本身也是一種安全隱患,對此,出現了很多將配置內容外部化的框架和工具。
為了能夠更合理地重寫各屬性的值,Spring Boot 使用了下面的屬性載入順序:

  1. 在命令列中能夠傳入的引數
  2. SPRING_APPLICATION_JSON 中的屬性。SPRING_APPLICATION_JSON 是以JSON格式配置在系統環境變數中的內容
  3. java:comp/env 中的JNDI屬性
  4. Java 的系統屬性,可以通過System.getProperties()獲得的內容
  5. 作業系統的環境變數
  6. 通過random.*配置的隨記屬性
  7. 位於當前應用ja包之外,針對不同{profile} 家門口的配置檔案內容,例如application-{profile}.properties或是YAML定義的配置檔案。
  8. 位於當前應用ja包之內,針對不同{profile} 家門口的配置檔案內容,例如application-{profile}.properties或是YAML定義的配置檔案。
  9. 位於當前jar包之外的application.properties和YAML配置內容
  10. 位於當前jar包之內的application.properties和YAML配置內容
  11. 在@Configuration註解修改的類中,通過@PropertySource註解定義的屬性
  12. 應用預設屬性,使用SpringApplication.setDefaultProperties定義的內容

數字越小優先順序越高。

可以看到,其中第7項和第9項都是從應用jar包之外讀取配置檔案,所以,實現外部化
配置低的原理就是從此切入,為其制定外部配置檔案的載入位置來取代jar包之內的配置內容。

2.5.6監控與管理

由於部署應用的數量成倍增長,系統及全中出現故障低的頻率也變得越來越高,雖然在高可用機制的保護
下,個別故障不會影響系統的對外服務,但是這些頻繁出現的故障需要做到高效運維,需要實現一套自動
化的監控運維機制。

這套機制的執行基礎就是不間斷的收集各個微服務應用的各項指標情況,並根據這些基礎指標資訊來制定監
控和預警規則,更進一步甚至作嘔到哦一些自動畫的運維操作等。

Spring Boot除了強大的快速開發功能之外,還因為 Starter POMs中提供了一個特殊依賴模組 ——
spring-boot-starter-actuator。
引入該模組能夠自動為Spring Boot 構建訂單應用提供一系列用於監控的端點。同時,Spring Cloud 在實
現各個微服務元件的時候,進一步為該模組做了不少擴充套件。

2.5.6.1初始actuator

引入模組:

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

啟動服務後,訪問 /health 檢視監控資訊。

注意:
如果訪問/health 顯示資訊過少,如:{“status”:”UP”}, 其他/beans , /env 返回401 ,是由於許可權限制。
需要在 application.properties,加入:management.security.enabled=false

在沒有引入其他依賴之前,該的端點的內容較為簡單,後續我們在使用Spring Cloud 的各個元件之後,它
的返回會變得非常豐富,這些內容將幫助我們制定更為個性化的監控策略。

2.5.6.2原生端點

根據端點的作用,可以將原生端點分為以下三大類:

  • 應用配置類:獲取應用程式中載入的應用配置、環境變數、自動化配置報告等與Spring Boot應用密 切相關的配置類資訊
  • 度量指標類:獲取應用程式執行過程中用於監控的度量指標,比如記憶體資訊、執行緒池資訊、HTTP請求統計等。
  • 操作控制類:提供了對應用的關閉等操作類功能

    2.5.6.2.1應用配置類

    由於現在開發中使用Spring的配置,大多是通過包掃描和自動化配置,這使得這個應用的例項建立和依賴
    關係等資訊被離散到了各個配置類的註解上,分析整個應用中資源和例項的各種關係變得非常困難。

這類端點可以幫助我們輕鬆獲取一系列關於Spring應用配置內容的詳細報告:

  • /autoconfig: 該端點用來獲取應用的自動化配置報告,包括自動化配置的候選項。可以檢視配置沒有生效的原因
  • positiveMatches : 返回的是條件匹配成功的自動化配置
  • negativeMatches : 返回的是條件匹配不成功的自動化配置
  • /beans : 該端點用來獲取應用上下文中建立的所有Bean.
    bean : Bean 的名稱
    scope : Bean 的作用域
    type : Bean 的java型別
    resource : class 檔案的具體路徑
    dependencies : 依賴的bean名稱
  • /configprops : 獲取應用中配置的屬性資訊報告,關閉該端點:(endpoints.configprops.enabled=false)
    prefix : 屬性的配置字首
    properties : 各個屬性的名稱和值
  • /env : 獲取應用所有可用的環境屬性報告。
    包括環境變數、JVM屬性、應用的配置屬性、命令列中的引數。
    可以配合@ConfigurationProperties註解將它們引入達到應用程式中進行使用。
    另外,為了配置屬性安全,可以配置password、secret、key這些關鍵詞,這樣該端點在返回它們的時候
    會使用 * 來替代實際的屬性值。

  • /mappings : 返回所有Spring MVC 的控制器對映關係報告。
    bean: 該對映關係的請求處理器
    method:表示了該對映關係的具體處理類和處理函式

  • /info : 返回一些應用自定義的資訊,預設只會返回一個空的JSON內容。
    可以在application.properties 配置檔案中通過 info 字首來設定一些屬性,如:
info.bookName=spring
info.author=test

請求返回:{“author”:”test”,”bookName”:”spring”}

2.5.6.2.2 度量指標類

提供動態變化的,應用程式在執行過程中的一些快照資訊,比如記憶體使用情況、HTTP請求統計、外部資源指標等,這些對監控系統非常有幫助。

  • /metrics : 返回當前應用的各類重要度量指標,如記憶體資訊、執行緒資訊、垃圾回收資訊等
    gauge.* : HTTP請求的效能指標之一,反應一個絕對數值。gauge.response.hello”:7.0 ,表示上
    一次hello請求的延遲時間為5毫秒。
    counter.* : HTTP請求的效能指標之一,主要作為計數器來使用,記錄了增加量和減少量。
    counter.status.200.hello : 11,代表了hello請求返回200狀態的次數為11。
  • /health : 獲取應用的各類健康指標資訊。
    在spring-boot-starter-actuator 模組中國自帶實現了一些常用資源的健康指標檢測器,這些檢測器都通過
    HealthIndicator介面實現,並且會根據依賴關係的引入實現自動化裝配,例如:
    這裡寫圖片描述

自己實現一個採集健康資訊的檢測器:

@Component
public class TestHealth implements HealthIndicator{

    @Override
    public Health health() {
        int errorCode = check();
        if(errorCode != 0)
            return Health.down().withDetail("Error Code", errorCode).build();
        return Health.up().build();
    }

    private int check() {
        return 0;
    }

}

再訪問/health ,返回結果:

{"status":"UP","testHealth":{"status":"UP"},"diskSpace":{"status":"UP","total":27808194560,"free":4236460032,"threshold":10485760}}
  • /dump : 暴露程式執行中的執行緒資訊。它使用 java.lang.management.ThreadMXBean的
    dumpAllThreads 方法來返回所有含有同步資訊的活動執行緒詳情。
  • /trace : 返回基本的HTTP跟蹤資訊。預設情況下,跟蹤資訊的儲存採用
    org.springframework.boot.actuate.trace.InMemoryTraceRepository實現的記憶體方式,始終儲存最近
    的100條請求記錄。

    2.5.6.2.3操作控制類

    在原生端點中,只提供了一個用來關閉應用的端點: /shutddown (在後續我們引入了Eureka之後,會引
    入更多控制端點)。可以通過配置開啟:
    endpoints.shutdown.enabled=true
    之後通過post請求訪問 /shutdown 可以關閉應用,真正在線上使用的時候,需要對其加入一定的保護機
    制,比如定製actuator的端點路徑、這鞥個Spring Security進行安全校驗等。