日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

深入学习微框架:Spring Boot

發布時間:2025/3/21 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入学习微框架:Spring Boot 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Boot致力于在蓬勃發展的快速應用開發領域(rapid application development)成為領導者。

?

?

多年以來,Spring IO平臺飽受非議的一點就是大量的XML配置以及復雜的依賴管理。在去年的SpringOne 2GX會議上,Pivotal的CTO Adrian Colyer回應了這些批評,并且特別提到該平臺將來的目標之一就是實現免XML配置的開發體驗。Boot所實現的功能超出了這個任務的描述,開發人員不僅不再需要編寫XML,而且在一些場景中甚至不需要編寫繁瑣的import語句。在對外公開的beta版本剛剛發布之時,Boot描述了如何使用該框架在140個字符內實現可運行的web應用,從而獲得了極大的關注度,該樣例發表在tweet上。

?

然而,Spring Boot并不是要成為Spring IO平臺里面眾多“Foundation”層項目的替代者。Spring Boot的目標不在于為已解決的問題域提供新的解決方案,而是為平臺帶來另一種開發體驗,從而簡化對這些已有技術的使用。對于已經熟悉Spring生態系統的開發人員來說,Boot是一個很理想的選擇,不過對于采用Spring技術的新人來說,Boot提供一種更簡潔的方式來使用這些技術。

?

在追求開發體驗的提升方面,Spring Boot,甚至可以說整個Spring生態系統都使用到了Groovy編程語言。Boot所提供的眾多便捷功能,都是借助于Groovy強大的MetaObject協議、可插拔的AST轉換過程以及內置的依賴解決方案引擎所實現的。在其核心的編譯模型之中,Boot使用Groovy來構建工程文件,所以它可以使用通用的導入和樣板方法(如類的main方法)對類所生成的字節碼進行裝飾(decorate)。這樣使用Boot編寫的應用就能保持非常簡潔,卻依然可以提供眾多的功能。

?

安裝Boot

從最根本上來講,Spring Boot就是一些庫的集合,它能夠被任意項目的構建系統所使用。簡便起見,該框架也提供了命令行界面,它可以用來運行和測試Boot應用。框架的發布版本,包括集成的CLI(命令行界面),可以在Spring倉庫中手動下載和安裝。一種更為簡便的方式是使用Groovy環境管理器(Groovy enVironment Manager,GVM),它會處理Boot版本的安裝和管理。Boot及其CLI可以通過GVM的命令行gvm install springboot進行安裝。在OS X上安裝Boot可以使用Homebrew包管理器。為了完成安裝,首先要使用brew tap pivotal/tap切換到Pivotal倉庫中,然后執行brew install springboot命令。

要進行打包和分發的工程會依賴于像Maven或Gradle這樣的構建系統。為了簡化依賴圖,Boot的功能是模塊化的,通過導入Boot所謂的“starter”模塊,可以將許多的依賴添加到工程之中。為了更容易地管理依賴版本和使用默認配置,框架提供了一個parent POM,工程可以繼承它。Spring Boot工程的樣例POM文件定義如程序清單1所示。

程序清單1

<?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.example</groupId><artifactId>myproject</artifactId><version>1.0.0-SNAPSHOT</version><!-- Inherit defaults from Spring Boot --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.0.0.RC1</version></parent><!-- Add typical dependencies for a web application --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies><repositories><repository><id>spring-snapshots</id><url>http://repo.spring.io/libs-snapshot</url></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><url>http://repo.spring.io/libs-snapshot</url></pluginRepository></pluginRepositories><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>

為了實現更為簡單的構建配置,開發人員可以使用Gradle構建系統中簡潔的Groovy DSL,如程序清單1.1所示。

程序清單1.1

buildscript {repositories {maven { url "http://repo.spring.io/libs-snapshot" }mavenCentral()}dependencies {classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.0.RC1")} }apply plugin: 'java' apply plugin: 'spring-boot'repositories {mavenCentral()maven { url "http://repo.spring.io/libs-snapshot" } }dependencies {compile 'org.springframework.boot:spring-boot-starter-actuator:1.0.0.RC1' }

為了快速地搭建和運行Boot工程,Pivotal提供了稱之為“Spring Initializr” 的web界面,用于下載預先定義好的Maven或Gradle構建配置。我們也可以使用Lazybones模板實現快速起步,在執行lazybones create spring-boot-actuator my-app命令后,它會為Boot應用創建必要的工程結構以及gradle構建文件。

開發Spring Boot應用

Spring Boot在剛剛公開宣布之后就將一個樣例發布到了Twitter上,它目前成為了最流行的一個應用樣例。它的全部描述如程序清單1.2所示,一個非常簡單的Groovy文件可以生成功能強大的以Spring為后端的web應用。

程序清單1.2

@RestController class App {@RequestMapping("/")String home() {"hello"} }

這個應用可以通過spring run App.groovy命令在Spring Boot CLI中運行。Boot會分析文件并根據各種“編譯器自動配置(compiler auto-configuration)”標示符來確定其意圖是生成Web應用。然后,它會在一個嵌入式的Tomcat中啟動Spring應用上下文,并且使用默認的8080端口。打開瀏覽器并導航到給定的URL,隨后將會加載一個頁面并展現簡單的文本響應:“hello”。提供默認應用上下文以及嵌入式容器的這些過程,能夠讓開發人員更加關注于開發應用以及業務邏輯,從而不用再關心繁瑣的樣板式配置。

Boot能夠自動確定類所需的功能,這一點使其成為了強大的快速應用開發工具。當應用在Boot CLI中執行時,它們在使用內部的Groovy編譯器進行構建,這個編譯器可以在字節碼生成的時候以編碼的方式探查并修改類。通過這種方式,使用CLI的開發人員不僅可以省去定義默認配置,在一定程度上甚至可以不用定義特定的導入語句,它們可以在編譯的過程中識別出來并自動進行添加。除此之外,當應用在CLI中運行時,Groovy內置的依賴管理器,“Grape”,將會解析編譯期和運行時的類路徑依賴,與Boot編譯器的自動配置機制類似。這種方式不僅使得框架更加對用戶友好,而且能夠讓不同版本的Spring Boot與特定版本的來自于Spring IO平臺的庫相匹配,這樣一來開發人員就不用關心如何管理復雜的依賴圖和版本結構了。另外,它還有助于快速原型的開發并生成概念原型的工程代碼。

對于不是使用CLI構建的工程,Boot提供了許多的“starter”模塊,它們定義了一組依賴,這些依賴能夠添加到構建系統之中,從而解析框架及其父平臺所需的特定類庫。例如,spring-boot-starter-actuator依賴會引入一組基本的Spring項目,從而實現應用的快速配置和即時可用。關于這種依賴,值得強調的一點就是當開發Web應用,尤其是RESTful Web服務的時候,如果包含了spring-boot-starter-web依賴,它就會為你提供啟動嵌入式Tomcat容器的自動化配置,并且提供對微服務應用有價值的端點信息,如服務器信息、應用指標(metrics)以及環境詳情。除此之外,如果引入spring-boot-starter-security模塊的話,actuator會自動配置Spring Security,從而為應用提供基本的認證以及其他高級的安全特性。它還會為應用結構引入一個內部的審計框架,這個框架可以用來生成報告或其他的用途,比如開發認證失敗的鎖定策略。

為了闡述在Java Maven工程中,如何快速地使Spring Web工程準備就緒,考慮一下程序清單1.3中的應用程序代碼。

程序清單1.3

package com.infoq.springboot;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.web.bind.annotation.*;@RestController @EnableAutoConfiguration public class Application {@RequestMapping("/")public String home() {return "Hello";}public static void main(String[] args) {SpringApplication.run(Application.class, args);} }

在Application類上的@EnableAutoConfiguration注解會告知Boot要采用一種特定的方式來對應用進行配置。這種方法會將其他樣板式的配置均假設為框架默認的約定,因此能夠聚焦于如何盡快地使應用準備就緒以便運行起來。Application類是可運行的,因此,當我們以Java Application的方式運行這個類時,就能啟動該應用及其嵌入式的容器,這樣也能實現即時地開發。

為了發布版本而構建工程時,Boot的Maven和Gradle插件可以嵌入(hook)到這些構建系統的打包過程中,以生成可執行的“胖jar包(fat jar)”,這種jar包含了工程的所有依賴并且能夠以可運行jar的方式執行。使用Maven打包Boot應用只需運行mvn package命令,與之類似,使用Gradle時,執行gradle build命令將會在構建的目標地址下生成可運行的jar。

開發微服務

Boot對Spring應用的開發進行了簡化,提供了模塊化方式導入依賴的能力,強調了開發RESTful Web服務的功能并提供了生成可運行jar的能力,這一切都清晰地表明在開發可部署的微服務方面Boot框架是一個強大的工具。正如前面的例子所示,借助于Boot,讓一個RESTful Web工程運行起來是一件很容易的事情;不過,為了了解Boot所有潛在的功能,我們會闡述在開發完整功能的微服務時,會遇到的所有繁瑣的事情。在企業級基礎設施領域,微服務是一種越來越流行的應用架構,因為它能夠實現快速開發、更小的代碼庫、企業級集成以及模塊化部署。有眾多的框架致力于該領域的開發,該章節將會討論使用Boot如何簡化這一過程。

數據訪問

我們可以基于各種目的來構建微服務,但有一點是肯定的,那就是大多數都需要讀取和寫入數據庫的能力。Spring Boot使數據庫集成變成了一項非常簡單的任務,因為它具有自動配置Spring Data以訪問數據庫的能力。只需在你的工程中將spring-boot-starter-data-jpa包含進來,Boot的自動配置引擎就能探測到你的工程需要數據訪問功能,并且會在Spring應用上下文中創建必要的Bean,這樣你就可以使用Repository和服務了。為了更具體地闡述這一點,請參見程序清單1.4中的Gradle構建文件,它列出了一個基于Groovy的微服務web應用的構建結構,該應用使用了Spring Data對JPA的支持來實現數據訪問。

程序清單1.4

buildscript {repositories {maven { url "http://repo.spring.io/libs-snapshot" }mavenCentral()}dependencies {classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.0.RC1")} }apply plugin: 'groovy' apply plugin: 'spring-boot'repositories {mavenCentral()maven { url "http://repo.spring.io/libs-snapshot" } }ext {springBootVersion = "1.0.0.RC1" }dependencies {compile 'org.codehaus.groovy:groovy-all:2.2.1'compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"compile "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" }

在這個配置中,Boot的actuator模塊提供了對hsqldb的依賴,這會搭建所有必要的依賴——包括模式的創建——因此Spring Data可以使用這個內存數據庫作為數據源。這種簡便的方式能夠讓開發人員免于在開發期創建和管理復雜的XML配置,進而能夠快速地開發數據庫驅動的微服務。如果在classpath中有H2或Derby數據庫的話,這種自動化配置也會生效。Boot所提供的另一個便利之處就是能夠快速簡便地使用相關數據啟動應用的數據庫模式。這在開發期是非常有用的,此時數據庫可能是在內存中或者是不穩定的,開發人員需要保證的是在應用啟動的時候能夠訪問到這些特定的數據。為了闡述這一點,考慮一下程序清單1.5中的示例JPA實體,它代表了微服務所提供的“User”數據結構。

程序清單1.5

@Entity class User {@Id@GeneratedValueLong idString usernameString firstNameString lastNameDate createdDateDate lastAccessedBoolean isActive = Boolean.TRUE }

為了啟用代表User對象的通用數據,我們只需創建一個名為schema.sql或data.sql的文件,并將其包含在classpath之中。這個文件會在模式創建完成之后執行,所以基于程序清單1.5所給出的實體,我們可以使用SQL語句啟用一個用戶賬號,如程序清單1.6所示。

程序清單1.6

insert into user(username, first_name, last_name, created_date) values ('danveloper', 'Dan', 'Woods', now())

在啟動的時候,我們所提供的SQL代碼會執行,這樣就能確保有一個測試賬號可以使用。微服務此時已經具有了數據訪問的起始點,程序清單1.7展現了如何按照Spring Data的開發模式創建Repository接口,該接口會作為User實體的數據訪問對象(Data Access Object)。

程序清單1.7

public interface UserRepository extends CrudRepository<User, Long> { }

CrudRepository提供了一些通用的接口方法來創建、查詢、更新以及刪除對象和對象集合。應用所需的其他特定功能可以按照Spring Data的Repository開發約定進行定義。一旦UserRepository接口創建成功,Boot的spring-data-jpa層會在工程中探測到它,并將其添加到Spring應用上下文之中,這樣對于controller和sevice對象來說,它就成為可以進行自動注入的可選對象。這種自動化的配置只有在Boot應用要求按照這種方式初始化的時候才生效,這是通過存在@EnableAutoConfiguration注解來標識的。借助程序清單1.8中所實現的controller,微服務現在就可以定義RESTful端點了,服務的使用者可以獲取到User的列表或單個User。

程序清單1.8

@RestController @EnableAutoConfiguration @RequestMapping("/user") class UserController {@AutowiredUserRepository repository@RequestMapping(method=[RequestMethod.GET])def get(Long id) {id ? repository.findOne(id) : repository.findAll()}public static void main(String[] args) {SpringApplication.run UserController, args} }

在啟動的時候,應用將會輸出日志,表明Hibernate按照User實體的定義創建數據庫結構,在應用初始化的最后,Boot還會從schema.sql文件中導入數據。

在開發微服務應用時,需要特別注意的一點是使用了@RequestMapping注解。這不是Boot特定的注解。不過,因為Boot安裝了自己的端點以監控應用的性能、健康情況以及配置,所以需要確保應用的代碼不要與這些內置的提供詳情的路徑解析相沖突。鑒于此,如果有從請求路徑中解析屬性的需求(在我們的場景中,也就是user的id屬性),那么我們需要仔細考慮這個動態的屬性解析會對微服務的其他行為產生什么影響。在本例中,只是簡單地將controller映射到/user端點而不是根上下文,就能允許Boot的端點也可以進行訪問。

微服務所提供的數據并不一定全部適合關系型結構,針對這一點Spring Boot也暴露了一些模塊,從而讓開發人員可以使用Spring Data的MongoDB和Redis項目,不過依然采取特定的方式來進行配置。Spring Data用來定義數據訪問對象(Data Access Object)的高層框架,這樣快速切換JPA與非JPA數據源會變得非常容易。參見程序清單1.9,它展現了一個重新定義的UserRepository接口,這個接口設計為使用MongoDB取代JPA。

程序清單1.9

public interface UserRepository extends MongoRepository<User, Long> { }

MongoRepository接口也擴展了CrudRepository,因此微服務的Controller代碼,也就是程序清單1.8所示并不需要修改。為了實現與MongoDB的集成,工程唯一要做的就是在應用的classpath中包含spring-boot-starter-data-mongodb。程序清單1.4所示的Gradle構建文件需要稍微調整一下依賴的部分,如程序清單1.10所示。

程序清單1.10

dependencies {compile 'org.codehaus.groovy:groovy-all:2.2.1'compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"compile "org.springframework.boot:spring-boot-starter-data-mongodb:$springBootVersion"compile "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" }

MongoDB依賴都置于classpath之中以后,Boot將會自動配置Spring Data連接到localhost上的數據庫,并且默認的數據庫名為test。在這個庫中,將會自動創建User集合(按照MongoDB的標準),微服務現在就能使用MongoDB作為后端了。對非JPA的數據存儲來說,初始化數據比其他的方式更為簡單,這主要是因為它不能針對MongoDB的文檔存儲和Redis的鍵值存儲運行SQL文件。鑒于Spring Data會使用這些存儲的持久化實例,這就意味著開發期創建的數據需要在重啟后保留。為了持久化數據,我們需要修改微服務的controller,這樣服務的使用者就能創建User實例了。我們也可以將微服務的UserController進行修改,使其符合通用的RESTful API結構,讓controller以不同的方式處理不同的HTTP方法。程序清單1.11展現了為controller添加創建新User實例的功能。

程序清單1.11

@RestController @RequestMapping("/user") @EnableAutoConfiguration class UserController {@AutowiredUserRepository repository@RequestMapping(method=[RequestMethod.GET])def get(Long id) {id ? repository.findOne(id) : repository.findAll()}@RequestMapping(method=[RequestMethod.POST])def create(@RequestBody User user) {repository.save useruser}public static void main(String[] args) {SpringApplication.run UserController, args} }

當微服務的使用者往應用的端點上發送一個HTTP POST請求時,Spring將會把請求體轉換為User實例。代碼接下來會使用UserRepository將這個對象存儲到MongoDB集合之中。使用curl創建User實例的樣例如程序清單1.12所示。

程序清單1.12

curl -v -H "Content-Type: application/json" -d "{ \"username\": \"danveloper\", \"firstName\": \"Dan\", \"lastName\": \"Woods\", \"createdDate\": \"2014-02-02T00:00:00\" }" http://localhost:8080/user

按照Boot針對Mongo數據源的特定配置,新的User實例默認會持久化到本地Mongo實例的test數據庫的user集合之中。如果我們打開web瀏覽器并對微服務發起一個HTTP GET請求,我們就能看到所創建的user存在于返回的列表之中。

配置

我們可以很快地重寫Spring Boot的默認配置。默認情況下,應用的配置可以使用Java屬性文件來進行定義,這個文件名為application.properties并且位于應用的classpath根目錄下。不過,一種更好的方式是使用?YAML配置,它提供了結構化以及嵌套的配置。在應用的運行時類路徑之中包含snakeyaml之后,你的工程就可以在application.yml文件中直接定義配置了。為了詳述這一點,考慮程序清單1.13的示例YAML配置,這里列出了應用的嵌入式HTTP服務器(默認是Tomcat,也可選擇Jetty)的各種設置項。

程序清單1.13

# Server settings (ServerProperties) server:port: 8080address: 127.0.0.1sessionTimeout: 30contextPath: /# Tomcat specificstomcat:accessLogEnabled: falseprotocolHeader: x-forwarded-protoremoteIpHeader: x-forwarded-forbasedir:backgroundProcessorDelay: 30 # secs

允許重寫Boot的自動化配置,這一點能夠使你的應用從原型轉化為真正的產品,Boot使用相同的application.yml文件進行配置,這樣就會非常容易。自動化配置的指令被設計的盡可能簡短,所以當使用actuator構建微服務時,會安裝一個配置屬性的端點,也就是/configprops,當確定哪些指令需要重寫時可以進行參考。如果我們的微服務要使用持久化數據源,如MySQL,那么只需將MySQL的Java驅動添加到運行時classpath中,然后在application.yml中添加必要的配置指令即可,如程序清單1.14所示。

程序清單1.14

spring:datasource:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/proddb username: rootpassword

在一些場景下你可能需要更為靈活的配置,Boot允許你通過Java的系統屬性(System properties)重寫很多它的默認配置。例如,如果你的應用需要在部署到產品化環境中使用不同的數據庫用戶,那么username配置指令可以通過標準的Java系統屬性傳入到應用之中,而這需要切換到命令行中執行-Dspring.datasource.username=user。關于這一點更為現實的場景是云部署環境,如Cloud Foundry或Heroku,這些平臺需要應用啟動特定的HTTP端口,這一點通過操作系統的環境變量可以實現。Boot能夠從系統屬性繼承得到配置,這樣你的應用就可以在命令行中使用-Dserver.port=$PORT來得到HTTP端口。在開發微服務時,這是一種相當有用的特性,因為它可以讓微服務應用運行在各種環境配置之中。

外部化配置

微服務必須要支持的很重要的一點就是外部化配置。這種配置可以包含任何的內容,從占位符信息到數據庫配置等等,在初始規劃和構建應用原型時,這是必須要考慮的架構內容。在Spring IO平臺中,已經存在各種導入配置的策略,但是應用能夠以多種方式使用配置所造成的后果往往是產生冗長的編碼性耦合。

Boot一個很棒的特性在于它能管理外部化的配置并將其轉換為對象結構,這個對象可以在整個應用上下文中使用。創建一個簡單老式的Java/Groovy對象(Plain Old Java/Groovy Object),并使用@ConfigurationProperties注解,那么這個對象就能使用Boot配置結構中預先定義的name名下的配置項。更具體一點來講,考慮一下程序清單1.15中的POGO,它能夠得到application.key下的配置指令。

程序清單1.15

@ConfigurationProperties(name = "application") class ApplicationProperties {String nameString version }

當ApplicationProperties對象在Spring上下文中創建完成之后,Boot將會識別出它是一個配置對象,并且會按照運行時classpath之中application.properties或application.yml文件中的配置指令填充它的屬性。因此,如果我們在微服務的application.yml文件中添加application內容區的話,如程序清單1.16所示,那么我們就可以在應用的其他部分以編程的方式訪問這些配置指令。

程序清單1.16

application:name: sb-ms-custdeplversion: 0.1-CUSTOMER

這些配置指令可以有各種用途,要訪問這些指令的唯一要求就是代表它們的POJO/POGO必須是Spring應用上下文的成員。Boot能夠將一個controller作為Spring Java配置對象,這樣就能很容易地管理配置bean與應用上下文的集成,如程序清單1.17所示。

程序清單1.17

@RestController @Configuration @RequestMapping("/appinfo") @EnableAutoConfiguration class AppInfoController {@AutowiredApplicationProperties applicationProperties@RequestMapping(method=[RequestMethod.GET])def get() {[name: applicationProperties.name,version: applicationProperties.version]}@BeanApplicationProperties applicationProperties() {new ApplicationProperties()}public static void main(String[] args) {SpringApplication.run UserController, args} }

程序清單1.17中的樣例代碼可能有些牽強,不過,即便是在更為復雜的場景下,如何使用Boot來訪問應用特定配置的原則是相同的。配置類也支持嵌套式的對象圖,這樣來自于配置中的深層數據就能更便利地進行訪問,也有了更好的語義。例如,如果我們想要得到的配置指令是application.根下的那些metrics key,那么可以在ApplicationProperties?POGO中添加一個嵌套對象來表示這些值,如程序清單1.18所示。

程序清單1.18

@ConfigurationProperties(name = "application") class ApplicationProperties {String nameString versionfinal Metrics metrics = new Metrics()static class Metrics {String dbExecutionTimeKey} }

現在,我們的application.yml文件可以如程序清單1.19所示,它在application.代碼塊中包含了metrics配置。

程序清單1.19

application:name: sb-ms-custdeplversion: 0.1-CUSTOMERmetrics:dbExecutionTimeKey: user.get.db.time

當我們需要訪問application.metrics.dbExecutionTimeKey的值時,能夠以編程的方式通過ApplicationProperties對象來進行訪問。

為了在整個應用之中使用application.properties或application.yml文件中的這些配置指令,我們并不是必須要將其轉換為對象圖。Boot也為Spring應用上下文提供了PropertySourcesPlaceholderConfiguration,這樣的話,來自于application.properties或application.yml文件的指令或者來自于Java系統的重寫屬性都可以作為Spring屬性占位符來使用。Spring的這種機制能夠讓你以一種特定的語法來為屬性定義占位符值,如果Spring發現了占位符配置的話,就會用這個配置來進行填充。作為示例,我們可以在controller中使用@Value注解來直接訪問application.metrics.dbExecutionTimeKey,如程序清單1.20所示。

程序清單1.20

@RestController @RequestMapping("/user") @EnableAutoConfiguration class UserController {@AutowiredUserRepository repository@AutowiredGaugeService gaugeService@Value('${application.metrics.dbExecutionTimeKey}')String dbExecutionKey@RequestMapping(method=[RequestMethod.GET])def get(Long id) {def start = new Date().timedef result = id ? repository.findOne(id) : repository.findAll()gaugeService.submit dbExecutionKey, new Date().time - startresult}public static void main(String[] args) {SpringApplication.run UserController, args} }

關于應用指標的報告,后面會有更為詳細的介紹,但現在重要的一點在于,理解@Value注解如何與Spring屬性占位符一起使用,使Boot能夠自動注入值,從而滿足這個微服務的特定配置需求。

安全

在微服務的開發中,對于完備安全場景的需求會持續增長。為了滿足這種需求,Boot引入了強大完整的Spring Security,并且提供了自動配置的功能,以快速簡便地啟用安全層。只需在應用的classpath中包含spring-boot-starter-security模塊就能使Boot引入一些安全特性,如跨站腳本防護(cross-site scripting protection)并且會添加頭信息以防止點擊劫持(click-jacking)。除此之外,添加一條簡單的配置指令就能啟用基本認證來保護你的應用,如程序清單1.21所示。

程序清單1.21

security:basic:enabled: true

Boot會為你提供一個默認的用戶賬號user和默認角色USER,并且會在應用啟動的時候在控制臺上輸出隨機生成的密碼。就像Boot的其他功能那樣,對于內置的user賬號,我們可以很容易地指定不同的用戶名和密碼(分別為“secured”和“foo”),這需要通過明確定義的配置指令來實現,如程序清單1.22所示。

程序清單1.22

security:basic:enabled: trueuser:name: securedpassword: foo

對于簡單的內部應用或開發原型來說,Boot內置的基礎設施能夠快速地在微服務中啟用基本認證,這是非常有用的。隨著需求的演化,你的應用毫無疑問會需要更細粒度的安全特性,如保護端點只能由特定的角色訪問。從這個角度來看,我們可能希望具有USER角色的調用者只能讀取數據(即GET請求),而對具有ADMIN角色的調用者可以讀取和寫入數據(即POST請求)。為了做到這一點,我們需要在工程的application.yml文件中禁用Boot的基本認證自動配置功能,并且定義我們自己的user和admin賬號以及對應的角色。當你的需求超過Boot所提供的默認功能時,它通常很快就能實現,這可以作為佐證這一點的又一個例子。為了更具體地闡述這一點,考慮一下程序清單1.23中的代碼。這個樣例可以闡述如何發揮Spring Security所有潛在的功能以及更為復雜的認證策略,如基于JDBC后端、OpenID或單點登錄(Single-Sign On)。

程序清單1.23

@RestController @RequestMapping("/user") @Configuration @EnableGlobalMethodSecurity(securedEnabled = true) @EnableAutoConfiguration class UserController extends WebSecurityConfigurerAdapter {@AutowiredUserRepository repository@RequestMapping(method = [GET])@Secured(['ROLE_USER'])def get(Long id) {id ? repository.findOne(id) : repository.findAll()}@RequestMapping(method = [POST])@Secured(['ROLE_ADMIN'])def create(@RequestBody User user) {repository.save useruser}@Overridevoid configure(AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication().withUser "user" password "password" roles "USER" and() withUser "admin" password "password" roles "USER", "ADMIN"}@Overridevoid configure(HttpSecurity http) throws Exception {BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint()entryPoint.realmName = "Spring Boot"http.exceptionHandling().authenticationEntryPoint(entryPoint)http.requestMatchers().antMatchers("/**").anyRequest().and().httpBasic().and().anonymous().disable().csrf().disable()}public static void main(String[] args) {SpringApplication.run UserController, args} }

在程序清單1.23的樣例之中,應用現在被明確地配置為要基于user和admin用戶賬號進行訪問,它們的密碼都是password,具有的角色分別是USER和ADMIN。微服務的GETPOST端點分別通過USER和ADMIN角色進行保護,這就意味著普通用戶可以訪問只讀的數據,而執行讀取-寫入操作的話,需要admin用戶憑證。

對于微服務來說,基本認證是很好的一個選擇,因為它遵循了很實用且廣泛使用的認證協議。換句話說,很多的API調用者,包括移動應用,能夠很容易地使用這一點來訪問你的微服務。當你的認證需求超過了基本認證的功能時(如OpenID或OAuth),微服務可以使用Spring Security的全部功能來滿足你的需求。

消息集成

在任何的應用中,消息(messaging)都是一種很強大的工具,在一點上,微服務當然也不能例外。使用消息驅動架構開發的應用能夠更好地支持可重用性和擴展性。Spring Boot能夠讓開發人員在編寫微服務時將消息作為架構的核心組成部分,它使用到了Spring IO平臺的企業集成模式(Enterprise Integration Patterns)實現,即Spring Integration。Spring Integration提供了開發消息驅動架構的基本結構,以及與分布式企業平臺集成的模塊。這種能力使得微服務可以使用來自抽象消息源的業務對象,這些消息源可以在應用內部,也可能是組織機構內部的其他服務所提供的。

盡管Boot并沒有提供明確的Spring上下文自動化配置,但是它為Spring Integration提供了一個starter模塊,它會負責引入Spring Integration項目的一系列依賴。這些依賴包括Spring Integration的核心庫(Core library)、HTTP模塊(用來進行面向HTTP的企業集成)、IP模塊(用來進行基于Socket的集成操作)、File模塊(用于進行文件系統集成)以及Stream模塊(用于支持使用Stream的操作,如stdin和stdout)。這個starter模塊為開發人員提供了健壯的消息功能的工具集,可以使已有的基礎設施適應微服務API。

除了starter模塊,Boot也為通過CLI構建的應用提供了編譯器自動配置的功能。對于需要快速構建微服務原型并驗證可行性的開發者來說,這種方式提供了一些捷徑。使用企業級平臺的應用可以快速地進行開發,在轉移到正式的工程和構建系統之前,就能確認其價值。使用Spring Boot和Spring Integration使一個消息驅動的微服務運行起來非常簡單,如程序清單1.24的樣例代碼所示。

程序清單1.24

@RestController @EnableIntegrationPatterns class App {@Beandef userLookupChannel() {new DirectChannel()}@Beandef userTemplate() {new MessagingTemplate(userLookupChannel())}@RequestMapping(method=[RequestMethod.GET])def get(@RequestParam(required=false) Long id) {userTemplate().convertSendAndReceive( id ? id : "")} }class User {Long id }@MessageEndpoint class UserLookupObject {@ServiceActivator(inputChannel="userLookupChannel")def get(Long id) {id ? new User(id:id) : new User()} }

使用消息驅動的方式來進行微服務的開發能提供很大的代碼可重用性,并且能夠與底層的服務提供者實現相解耦。在更為正式的場景之中,程序清單1.24的代碼可能會負責組合數據,這些數據可能來自于數據庫調用和企業組織中某個外部的服務集成。Spring Integration具有內置的設施用來進行負載路由(payload routing)和處理器鏈(handler chaining),這對于組合不同的數據來說,是一個很有吸引力的方案,我們的微服務可以作為一個數據的提供者(provider)。

提供度量指標

微服務最重要的一個特性可能就是為報表終端(reporting agent)提供度量指標。不像那些功能完備的Web應用,微服務是輕量級的,設計時可能就不會規劃提供報表界面或完備的接口來分析服務的活動。這種類型的操作最好是留給專門進行數據聚合和分析的應用,這些數據能夠用來進行穩定性、性能以及商務智能的監控。基于這樣的前提,微服務應該為這些工具提供端點,從而更加容易地獲取有關該服務活動的數據。而報表工具負責將數據聚合到一個視圖或報告中,對于關心數據的人這才是有意義的。

微服務的一些指標如穩定性和性能,對所有的應用都是通用的,但是與業務操作相關的指標必須由應用本身來具體進行管理。針對這一點,Spring Boot的actuator模塊為開發人員提供了一種機制,允許開發人員通過/metrics端點以編碼的方式暴露微服務狀態的細節。Boot將指標拆分為“counter”和“gauge”兩種類別:counter是所有以Number類型來展現的指標,而gauge是衡量雙精度計算的指標。為了讓微服務的開發人員更加容易地使用指標,Boot暴露了CounterService和GaugeService,它們可以自動織入到應用上下文之中。請參見程序清單1.25的樣例,它闡述了如何通過CounterService對外暴露點擊數。

程序清單1.25

@RestController @RequestMapping("/user") @EnableAutoConfiguration class UserController {@AutowiredUserRepository repository@AutowiredCounterService counterService@RequestMapping(method = [GET])def get() {get(null)}@RequestMapping(value="/{id}", method = [GET])def get(@PathVariable Long id) {counterService.increment id ? "queries.by.id.$id" : "queries.without.id"id ? repository.findOne(id) : repository.findAll()} }

在點擊/user端點時,有可能提供ID也有可能不提供ID,/metrics端點都會在counter.父節點下記錄新的key。例如,如果我們只是查詢/user端點而不帶有ID的話,那么就會注冊counter.queries.without.id指標。類似的,如果我們帶有ID的話,那么就會看到有一個counter.queries.by.id.<id>的key,它能用來標記對于給定的ID已經進行了多少次查詢。這些指標可能會有助于掌握最經常訪問的User對象并指導要采取的行為,如緩存或數據庫索引。類似于遞增指標的數值,CounterService也允許將指標的值將為零。這對于跟蹤打開的連接數或其他頻率分布(histographic)的測量都是很有用處的。

gauge是稍微有所不同的一種類型指標,它會進行探索性的計算或基于請求來確定值。如GaugeService的JavaDocs所述,“gauge”可以測量任意的值,從方法執行的次數到會議室的溫度。當需要為報表工具暴露細節時,這種類型的測量尤其適合于使用GaugeService。gauge的指標會在/metrics端點之下進行訪問,并且帶有gauge.前綴。它們的注冊方式與counter有些差別,如程序清單1.26所示。

程序清單1.26

@RestController @RequestMapping("/user") @EnableAutoConfiguration class UserController {@AutowiredUserRepository repository@AutowiredCounterService counterService@RequestMapping(method = [GET])def get() {get(null)}@RequestMapping(value="/{id}", method = [GET])def get(@PathVariable Long id) {def start = new Date().timedef result = id ? repository.findOne(id) : repository.findAll()def time = new Date().time - startgaugeService.submit("user.get.db.time", time.doubleValue())result} }

默認情況下,指標會存儲在一個易失的內存數據庫之中,但Boot同時也為應用上下文提供了MetricsRepository實現,它能支持更為持久化的行為。Boot自帶了一個RedisMetricsRepository,它能夠自動織入進來,從而將指標存儲到Redis值存儲之中,另外,可以編寫自定義的實現將指標存儲到任意的數據存儲形式之中。

Boot還提供了對Coda Hale Metrics庫的支持,它會將以特定名稱開頭的指標強制轉換為對應的Metrics類型。例如,如果有一個指標是以histogram.開頭,那么這個值將會作為Histogram對象類型。這種自動化的強制轉換對于meter.和timer.key也是有效的,而普通的指標將會作為Gauge類型。

一旦微服務的指標在Boot中進行了注冊,那么報表工具就可以通過/metrics端點來檢索它們。已命名的指標可以通過/metrics端點獲取,只需將指標的key名作為查詢字符串的一部分即可。例如,如果只是訪問gauge指標下的“user.get.db.time”,報表工具可以針對/metrics/gauge.user.get.db.time進行查詢。

打包Boot應用

正如前面所討論的,Boot提供了Maven和Gradle插件,它為構建系統的打包階段提供了一種鉤子(hook),以產生所謂的“胖jar”,在這種jar中包含了工程的所有依賴。當這個胖jar包執行時,應用將會運行在與工程開發期相同的嵌入式容器之中。這種簡便的方式能夠讓開發人員省去很多麻煩,因為他們的部署包在開發期和運行時環境之中具有相同的依賴結構。這也能夠緩解運維團隊的焦慮,他們不用擔心部署的場景,因為在部署時一個錯誤配置的運行時容器可能會帶有某個特定的依賴,而在項目的開發期所依賴的可能是另外一個。

為了在Maven下執行打包,只需執行mvn package命令。Spring Boot的插件會備份工程所創建的原始jar并且在文件名上添加“.original”。在這里,能夠得到可運行的jar,文件符合Maven artifact的命名約定,它可以按照工程最合適的方式進行部署。使用Gradle構建Boot工程同樣很簡單,只需執行標準的gradle build命令即可。類似于Maven,Boot插件在原有的打包任務之后使用Gradle安裝了一個生命周期事件,并且會在build/libs目錄下創建胖jar包。對所生成的胖jar包進行檢查的一種方式就是所有依賴的jar都會位于歸檔文件的lib/目錄下。

打包完成之后,胖jar包就能夠像其他可運行的jar文件那樣在命令行中執行了,也就是使用$JAVA_HOME/bin/java -jar path/to/myproject.jar命令。啟動后,Boot應用的日志將會顯示在控制臺上。

對于需要部署到傳統servlet容器之中的應用,Boot提供了一種方式以編碼的方式初始化Web配置。為了使用這一點,Boot提供了可選的WebApplicationInitializer,它會使用servlet容器來注冊應用,這會通過Servlet 3.0 API以編碼的方式注冊servlet并且會用到ServletContext。通過提供SpringBootServletInitializer的子類,Boot應用能夠使用嵌入的Spring上下文來注冊配置,這個Spring上下文是在容器初始化的時候創建的。為了闡述這個功能,考慮程序清單1.27中的示例代碼。

程序清單1.27

@RestController @EnableAutoConfiguration class Application extends SpringBootServletInitializer {@RequestMapping(method = RequestMethod.GET)String get() {"home"}static void main(String[] args) {SpringApplication.run this, args}@OverrideSpringApplicationBuilder configure(SpringApplicationBuilder application) {application.sources Application} }

Application類中被重寫的configure方法就是使用嵌入式的Spring上下文注冊應用的地方。在更為正式的場景之中,這個方法可能會用來注冊Spring Java配置類,它會定義應用中所有controller和服務的bean。

當將應用打包部署到servlet容器之中時,工程要構建為一個war文件。在Maven工程中,為了適應這一點,需要移除Boot插件,并且packaging需要明確定義為“war”類型,如程序清單1.28所示。

程序清單1.28

<?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.example</groupId><artifactId>myproject</artifactId><version>1.0.0-SNAPSHOT</version><packaging>war</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.0.0.RC1</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies><repositories><repository><id>spring-snapshots</id><url>http://repo.spring.io/libs-snapshot</url></repository></repositories> </project>

對這個工程執行mvn install命令會在target目錄下生成myproject-1.0.0-SNAPSHOT.war文件。使用Gradle構建的工程可以使用Gradle War Plugin,它為構建war文件暴露了一個war任務。類似于Maven的配置,Boot Gradle工程也需要移除所包含的Boot插件。產生war文件的示例Gradle構建腳本如程序清單1.29所示。

程序清單1.29

apply plugin: 'java' apply plugin: 'war'repositories {mavenCentral()maven { url "http://repo.spring.io/snapshot" }maven { url "http://repo.spring.io/milestone" } }ext {springBootVersion = '1.0.0.BUILD-SNAPSHOT' }dependencies {compile "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"compile "org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}" }

對于Boot工程,使用這個構建腳本運行Gradle的war任務將會在build/libs目錄下產生war文件。

不管是Maven還是Gradle的配置,一旦war文件產生,它就可以部署到任意兼容Servlet 3.0的應用服務器之中。部分兼容的容器包括Tomcat 7+、Jetty 8、Glassfish 3.x、JBoss AS 6.x/7.x以及Websphere 8.0。

延伸閱讀

Spring Boot團隊已經編寫了完整的指導和樣例來闡述框架的功能。Blog文章、參考資料以及API文檔都可以在Spring.IO網站上找到。項目的GitHub頁面上可以找到示例的工程,更為具體的細節可以閱讀Spring Boot的參考手冊。SpringSourceDev YouTube頻道有一個關于Spring Boot的webinar,它概述了這個項目的目標和功能。在去年在倫敦舉行的Groovy & Grails Exchange上,David Dawson做了一個使用Spring Boot開發微服務的演講。

?

總結

以上是生活随笔為你收集整理的深入学习微框架:Spring Boot的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。