天天看點

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    Spring Boot是一個廣泛用來建構Java微服務的架構,它基于Spring依賴注入架構來進行工作。Spring Boot允許開發人員使用更少的配置來建構微服務,同時架構本身能夠盡可能的減少開發人員的沖突,它和我們後面要介紹的兩個架構類似,它通過以下幾個方面幫助開發人員:

自動化配置,一般情況下都有預設配置

提供一組流行的starter依賴,友善開發人員使用

簡化應用打包

提升應用運作時的内省性(例如:Metrics與環境資訊)

    Spring以噩夢般的配置而聞名,雖然架構本身相比其他元件模型(EJB 1.x 和 2.x)簡單了不少,但是它也帶來了自己的配置模式。也就是說,如果想要正确的使用Spring,你需要深入了解如何進行XML配置、了解<code>JdbcTemplate</code>、<code>JmsTemplate</code>以及<code>BeanFactory</code>生命周期、了解<code>Servlet</code>監聽器,你以為掌握了這些就可以開始開發了嗎?實際上問題遠沒有結束,如果你要用Spring MVC編寫一個簡單的<code>hello world</code>,你還需要了解<code>DispatcherServlet</code>和一堆<code>Model-View-Controller</code>相關的類型。

    Spring Boot目标就是消除掉這些與業務無關的配置和概念,通過簡單的注解,你就能夠完成這些工作,當然如果你想繼續想以前一樣使用Spring,它也不會攔着你。

    Spring廣泛使用着,包括了大型企業應用,在應用中,使用者将會使用到不同的技術元件,包括:JDBC資料源、消息隊列、檔案系統以及應用緩存等。開發人員需要在需要這些功能時,停下來,仔細分析一下自己究竟需要什麼?需要的内容屬于哪個依賴(“哦,我需要JPA依賴”),然後花費大量的時間在依賴組織和排除上。

    Spring Boot提供了功能域(一批jar包依賴)的依賴,它讓開發人員聲明需要的功能,而不用去關系究竟如何處理依賴關系。這些starter可以允許開發人員直接使用這些功能:

JPA持久化

NoSQL資料庫支援,例如:MongoDB、Cassandra或者CouchBase

Redis緩存

Tomcat、Jetty或者Undertow的Servlet引擎

JTA事務

    通過直接添加一個starter,能夠讓開發人員獲得這個特性相關的一組依賴,而這些依賴的組合已經被驗證,省卻了開發人員的不少時間。

    Spring Boot是一組jar包和符合其約定的配置的建構塊,是以它不會運作在現有的應用伺服器中,而使用Spring Boot的大多數開發人員更喜歡的是直接運作的這種自包含的<code>jar</code>包。這意味着Spring Boot将所有的依賴和應用程式代碼都包裝到一個自包含的<code>jar</code>中,而這些jar包運作在一個平面的類加載器中。簡單的類加載體系使得開發人員更容易了解應用程式的啟動、依賴關系和日志輸出,但更重要的是,它有助于減少應用從建構到生産環境的步驟數量。這意味着開發人員不必将打包好的應用放置到應用伺服器中,而是直接運作這個standalone的應用,如果你需要<code>servlet</code>,那麼完全可以将其打包在應用内,使其為你服務。

    沒錯,一個簡單的<code>java -jar &lt;name.jar&gt;</code>就可以啟動你的應用了!Spring Boot、Dropwizard和WildFly Swarm都遵循将所有内容打包成可執行的<code>jar</code>模式。但是傳統的應用伺服器包含的管理能力,怎麼在這種模式下實作呢?

    Spring Boot推出了一個叫做<code>actuator</code>的子產品,它可以實作應用的名額統計。例如:我們可以收集日志、檢視名額、生成執行線程dump、顯示環境變量、了解gc以及顯示BeanFactory中配置的bean。可以通過<code>HTTP</code>或者<code>JMX</code>暴露這些資訊或者進行日志輸出。借助Spring Boot,我們可以利用Spring架構的功能、減少配置并快速開發應用并上線。

    說了這麼多,讓我們看看怎麼使用它。

Homebrew下: <code>brew tap pivotal/tap</code> <code>brew install springboot</code>

    一旦你安裝了Spring Boot CLI,你可以這樣檢查一下。

    如果你能看到版本的輸出,恭喜你,安裝成功了。接下來,在你希望建立工程的目錄下運作指令:<code>spring init --build maven --groupId com.murdock.examples --version 1.0 --java-version 1.8 --dependencies web --name hola-springboot hola-springboot</code>

在microservices-camp下運作。

    運作該指令後,将會在目前目錄下建立一個<code>hola-springboot</code>目錄,同時該目錄下包含了一個完整的Spring Boot程式,簡單的介紹一下這個指令中包含的内容。

--build

使用的建構工具,示例中是:maven

--groupId

maven坐标中的組Id,也就是代碼的包名,如果你想改包名,隻有在IDE中修改

--version

maven坐标中的version

--java-version

Java版本

--dependencies

這是一個有趣的參數,我們可以指定某種開發類型的依賴。比如:web就是指目前項目使用Spring MVC架構,預設基于内嵌的Tomcat(Jetty和Undertow作為可選)。其他的依賴或者starter,比如:<code>jpa</code>、<code>security</code>和<code>cassandra</code>

    進入到<code>hola-springboot</code>目錄中, 執行指令:<code>mvn spring-boot:run</code>,如果程式啟動,沒有報錯,你就能看到如下的日志:

    恭喜你!你快速的建立了一個Spring Boot應用,并且啟動了它,你甚至可以通路<code>http://localhost:8080</code>,你會看到如下内容

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    可以看到傳回了預設的出錯頁面,到目前為止,它除了這個什麼也做不了。接下來,我們就添加一些特性,比如:REST通路,做一個helloworld式的應用。

後續實踐内容與原文有不同,在操作性上要比原文具備更好的實踐性。

    現在我們擁有了一個可以運作的Spring Boot應用,讓我們為它添加一些簡單的功能。首先,我們想做的是,讓應用暴露一個位置是<code>api/holaV1</code>HTTP/REST端點,通路它将傳回 Hola Spring Boot @ X,而其中的 X 是運作應用的本機IP。

    在編寫代碼前,先将<code>hola-springboot</code>導入到IDE中,在<code>com.murdock.examples.holaspringboot</code>包下面建立一個類,名稱為<code>HolaRestControllerV1</code>。

    可以看到方法<code>hola()</code>傳回了我們需要的内容,一個簡單的字元串。

    到現在為止,我們隻是建立了一個名為<code>HolaRestControllerV1</code>的<code>POJO</code>,你可以寫一些單元測試去做驗證,而讓它暴露HTTP端點,則需要增加一些内容。

@RestController

這個注解告知Spring,該類是一個用于暴露HTTP端點的控制器(可以暴露GET、PUT和POST等基于HTTP協定的功能)

@RequestMapping

用于映射HTTP URI到對應的類或者方法

    通過添加這兩個注解,我們就可以使得原有的類具備了暴露HTTP端點的能力。針對上面的代碼,比如<code>@RequestMapping("/api")</code>代表着<code>HolaRestControllerV1</code>接受來自<code>/api</code>路徑的請求,當添加<code>@RequestMapping(method = RequestMethod.GET, value = "/holaV1", produces = "text/plain")</code>時,表示告知Spring在/holaV1(其實是/api/holaV1)暴露HTTP GET端點,該端點接受的類型是<code>text/plain</code>。Spring Boot将會使用内置的<code>Tomcat</code>運作,當然你也可以切換到<code>Jetty</code>或者<code>Undertow</code>。

    我們在<code>hola-springboot</code>目錄下,執行<code>mvn clean package spring-boot:run</code>,然後使用浏覽器通路<code>http://localhost:8080/api/holaV1</code>,如果一切正常,我們可以看到如下内容。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    現在這些傳回内容是寫死的,如果我們想個應用增加一些環境相關的配置,如何做呢?比如:可以替代 Hola 這個詞,比如使用 Guten Tag 德語,我們把這個應用部署給德國人用,我們需要一個将外部屬性注入給應用的途徑。

    Spring Boot可以很容易使用諸如:properties檔案、指令行參數和系統環境變量等作為外部的配置來源。我們甚至可以将這些配置屬性通過Spring Context綁定到類型執行個體上,例如:如果想将<code>helloapp.*</code>屬性綁定到<code>HolaRestController</code>,可以在類型上聲明<code>@ConfigurationProperties(prefix="helloapp")</code>,Spring Boot會自動嘗試将比如<code>helloapp.foo</code>或者<code>helloapp.bar</code>等這些屬性值綁定到類型執行個體的<code>foo</code>、<code>bar</code>等字段上。

    在Spring Initializer CLI建立的工程中,已經有了一個<code>application.properties</code>,我們就可以在這個檔案中定義新屬性,比如:<code>helloapp.saying</code>。

    建立一個新的控制器<code>HolaRestControllerV2</code>。

    停止之前運作的應用,然後在<code>hola-springboot</code>目錄下,繼續使用<code>mvn clean package spring-boot:run</code>來編譯工程,運作這個應用,然後使用浏覽器通路<code>http://localhost:8080/api/holaV2</code>,你會看到如下内容。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    我們現在通過更改外部配置檔案來使應用适應部署的環境,比如:調用服務的url、資料庫url和密碼以及消息隊列配置,這些都适合作為配置。但是也要把握度,不是所有的内容都适合放置在配置中,比如:應用在任何環境下都應該具備相同的逾時、線程池、重試等配置。

    一個Spring Boot應用搭建起來了,緊接着就是将其部署到生産環境,我們怎樣監控它呢?當我們想知道它運作的怎麼樣,我們該怎麼辦呢?除非我們讓應用向外暴露出Metrics,否則應用就會像黑盒子一樣。Spring Boot專門提供了一個starter -- <code>actuator</code>來完成這個工作。

    讓我們看看如何啟用<code>actuator</code>,啟用的過程非常簡單。在<code>hola-springboot/pom.xml</code>中依賴:

    然後在<code>hola-springboot/src/main/resources/application.properties</code>中增加一個配置(安全原因):

    随後,結束目前應用,在<code>hola-springboot</code>下運作:<code>mvn clean package spring-boot:run</code>重新編譯工程,啟動項目。

    我們可以通過浏覽器通路幾次<code>http://localhost:8080/api/holaV1</code>以及<code>http://localhost:8080/api/holaV2</code>,然後通路一下:<code>http://localhost:8080/metrics</code>,可以看到如下内容。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    類似這樣的URL還有許多:

<a href="http://localhost:8080/beans">http://localhost:8080/beans</a>

<a href="http://localhost:8080/env">http://localhost:8080/env</a>

<a href="http://localhost:8080/health">http://localhost:8080/health</a>

<a href="http://localhost:8080/metrics">http://localhost:8080/metrics</a>

<a href="http://localhost:8080/trace">http://localhost:8080/trace</a>

<a href="http://localhost:8080/mappings">http://localhost:8080/mappings</a>

    暴露出這些運作時資訊,使得開發人員在忙于業務開發的同時,更輕松擷取到系統資訊。

    到現在為止,我們還是以開發者視角使用maven來建構這個簡單的工程。如果我們需要将它部署到其他環境,比如:開發、測試或者生産環境,需要怎麼做呢?

    幸運的是,使用Spring Boot,我們可以輕松的釋出和建構,Spring Boot推薦單一、可執行的jar,而在這個jar中包括了所有的依賴,這些依賴的jar都會放置在應用的類路徑下。在<code>hola-springboot</code>下,運作<code>mvn clean package</code>,然後可以通過<code>java -jar</code>來運作。

    就是這樣,我們可以啟動這個應用,後續接下來介紹的<code>Dropwizard</code>和<code>WildFly Swarm</code>都使用類似的方式進行。

    在微服務環境下,每個服務都有提供功能的義務并服務好它的調用者。就像我們在第一章中談的,因為網絡的不确定性,建構分布式系統十分的困難,本章主要讨論一個服務怎樣調用到背景的服務。

在第五章中,将會讨論服務的柔性、适應性互動和調用

    接下來将擴充<code>hola-springboot</code>項目,完成服務的調用,但在此之前,我們先要搭建一個背景服務,完成類似下圖的互動。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務
背景服務的建構,将采用forge + WildFly的方式進行,比原文中寫一個Servlet部署到Jetty顯得更好 關于forge的安裝,在mac下:<code>brew install jboss-forge</code>

    通過以下方式,可以在<code>microservices-camp</code>下建立一個具備持久化能力的REST服務,它可以自由的部署到<code>WildFly</code>中。

    使用<code>forge</code>建構完成之後,可以将其導入到IDE中,如果觀察<code>BookEndpoint</code>這個類型,你會發現涉及到<code>CRUD</code>以及分頁查詢等邏輯已經完全具備了。

    通過上述指令,我們可以建構出一個<code>hola-backend.war</code>的應用,下面我們将其部署到<code>WildFly</code>中。<code>WildFly</code>的使用可以通過下載下傳到本地運作,但是由于涉及到兩個程序的互動,本文采用<code>Docker</code>的方式進行部署,讀者可以自行準備環境。

筆者準備了<code>WildFly</code>鏡像,可以簡單的運作起來 執行:<code>sudo docker run --name wildfly -it -p 9990:9990 -p 8080:8080 weipeng2k/wildfly-admin</code>,可以啟動一個<code>WildFly</code>,HTTP端口在8080,應用管理端口在9990 管理者賬号筆者已經建構在鏡像中:admin/Admin#hello1234

    登入到<code>WildFly</code>背景,通過管理界面,部署<code>hola-backend.war</code>。

    可以看到背景的更新日志,從中可以了解到應用部署正常。

    使用這種方式的好處在于開發階段如果有新的包生成直接進行上傳就好,如果想整體銷毀,直接停止删除容器即可,不會弄壞<code>WildFly</code>。下面使用chrome插件<code>Postman</code>建構<code>Book</code>資料,然後測試是否可用。

    新增資料測試。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    查詢資料測試。

    看來背景服務應用<code>hola-backend</code>工作正常,當然可以通過<code>WildFly</code>的管理界面查詢運作時資訊,這點和Spring Boot的actuator很像,但是産品化的體驗做的更好些。

    接下來在<code>hola-springboot</code>項目中建立<code>BookRestController</code>,使用<code>RestTemplate</code>來完成後端服務的互動。

    可以看到<code>BookRestController</code>将後端的host與port放在了配置中,而字首是<code>books</code>,那麼也就需要在<code>application.properties</code>中增加這些配置。

    接下來,打開浏覽器通路:<code>http://localhost:8080/api/books/1</code>,它将通路<code>hola-springboot</code>,而<code>hola-springboot</code>将會調用<code>hola-backend</code>,最終由<code>hola-springboot</code>輸出結果。

Java微服務開發指南 -- 使用Spring Boot建構微服務使用Spring Boot建構微服務

    通過本章的内容,我們學習了Spring Boot的基本知識,了解它與傳統的<code>WAR</code>和<code>EAR</code>不同的部署方式,以及如何使用外部資源來完成配置,并通過actuator暴露了Metrics,使用<code>RestTemplate</code>調用了另一個服務。如果你想了解跟多内容,可以參考下面的連結。

<a href="http://projects.spring.io/spring-boot/">Spring Boot</a>

<a href="http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/">Spring Boot Reference Guide</a>

<a href="https://www.manning.com/books/spring-boot-in-action">Spring Boot in Action</a>

<a href="https://github.com/spring-projects/spring-boot">Spring Boot on GitHub</a>