上篇文章總結了《深刻實踐Spring Boot》的第一部分,這篇文章介紹第二部分:分佈式應用開發,以及怎麼構建一個高性能的服務平臺。html
主要從如下幾個方面總結:前端
上篇文章提到了安全設計,使用Spring Security進行用戶驗證和權限驗證,但一個企業級的應用系統可能存在不少應用系統,每一個應用系統都須要設計安全管理,但不可能爲每個應用系統都設計一套安全管理,這樣不但耗時耗力,並且要作重複的工做,也不適宜創建統一的用戶中心。vue
可使用單點登陸SSO的方式創建一個登陸認證系統,而且實現對用戶的統一管理。本章在使用Spring Security安全管理的基礎上,再結合OAuth2認證受權協議來實現的,它不但適用於大型的分佈式管理系統,也適用於爲第三方提供統一的用戶管理和認證的平臺。java
做者給出了一個完整的實例,以模塊化的設計方式進行實現,整個demo的代碼能夠在github上查看。(https://github.com/chenfromsz/spring-boot-sso)mysql
我在本地運行了demo,經過chrome查看了系統間跳轉的過程,先說明下模塊的劃分,而後看下運行效果。git
項目 | 工程 | 類型 | 功能 |
---|---|---|---|
數據庫管理模塊 | mysql | 程序集成 | 數據庫管理 |
安全配置模塊 | security | 程序集成 | 安全策略配置和權限管理 |
登陸認證模塊 | login | Web應用 | SSO登陸認證(80) |
共享資源模塊 | resource | Web應用 | 共享資源(8083) |
客戶端應用1 | web1 | Web應用 | 客戶端1(8081) |
客戶端應用2 | web2 | Web應用 | 客戶端2(8082) |
訪問首頁時,跳轉到登陸頁面,輸入正確的帳號、密碼、驗證碼。
登陸成功後,跳轉到首頁:
github
訪問web1系統、web2系統時不須要從新登陸,會自動登陸:
web
「登陸認證模塊」主要包括驗證用戶帳號、集成OAuth2服務端端功能。spring
「安全配置模塊」是一個公共模塊,集成了SSO客戶端的安全策略配置和權限管理功能,供客戶端引用。sql
「數據庫管理模塊」是一個公共模塊,主要提供數據庫的訪問功能,供其餘模塊使用。
「共享資源模塊」提供了一個簡單的公共服務,2個客戶端應用可經過spring-cloud-zuul直接調用。
後面會重點介紹下登陸認證模塊,其餘模塊比較簡單,再也不過多介紹。
模塊化設計能夠提升代碼的複用性,避免重複開發,實例中的「數據庫管理模塊」和「安全配置模塊」能夠被其餘模塊共用,減小大部分重複工做。
做者的這種設計方式值得咱們學習,在之後的系統設計中,應多借鑑這種方式。
我畫了一個流程圖,先了解下用戶認證、權限驗證的基本過程:
整個處理流程,Spring Security都幫咱們自動實現了,咱們只須要對帳號中心數據源、權限中心數據源進行配置和擴展,另外,能夠對登陸頁面進行擴展,配置權限管理規則、防攻擊策略、記住登陸狀態。
爲了實現多個系統只需登陸一次,須要集成OAuth2。添加spring-cloud-starter-oauth2依賴,編寫一個配置類,繼承AuthorizationServerConfigurerAdapter,並聲明下@EnableAuthrizationServer來啓用OAuth2的認證服務器功能。
OAuth2有不少受權機制,本例中使用authorization_code機制,具體配置就不過多說明了,能夠參考下面的幾篇文章:
[1] 初步理解Spring Security並實踐
[2] security OAuth2.0 提供者實現原理
[3] jwt token介紹
[4] security OAuth2.0 jwt完美整合例子
有這樣一個問題,若是上傳文件,如上傳圖片,應該怎樣保存,保存在哪裏?
傳統的作法通常都保存在Web服務器所在機器中。但隨着業務的日益發展,可能上傳的文件會累積愈來愈多,單臺機器每每會不堪重負,再加上一些負載均衡的配置和服務,須要分佈式文件系統解決。
在諸多分佈式的文件系統中,FastDFS是比較優秀的分佈式文件系統。FastDFS是一個徹底開源的分佈式文件系統,使用比較簡單方便,並且性能也很優秀,存儲容量和訪問性能可按需求進行線性橫向擴展。
FastDFS服務端和客戶端的安排、配置、管理都比較簡單,書中描述的也比較詳細,就不在此贅述了。
Spring Cloud 是一套雲應用開發工具集,爲分佈式的微服務開發提供了一整套簡單易用的使用工具。Spring Cloud主要包括配置管理、服務發現、動態路由、負載均衡、斷路器、安全管理、事件總線、分佈式消息等組件的開發工具包。
Spring Cloud與Spring Boot 關係密切,可以臻於完美的幾何使用。
本章重點介紹了配置服務、發現服務、動態路由和斷路器、監控服務。
一個項目工程老是須要一些配置,好比,要配置服務器的端口、訪問數據庫的參數等。一個大型的分佈式系統可能存在不少這樣須要配置的項目工程,配置管理是一個龐大的工程,須要一個單獨的系統專門管理各個項目的配置。
經過Spring Cloud的配置管理,只需建立一個簡單的工程,就能夠實現分佈式配置管理服務,同時還支持在線更新。
第一步,配置管理服務器
引入spring-cloud-config-server依賴,建立一個主程序:
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigApplication{
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
配置文件的存儲目前支持使用本地存儲、Git以及Subversion等方式。以Git方式爲例,說明本地配置文件:
spring:
cloud:
config:
server:
git:
uri: https://github.com/chenfromsz/spring-cloud-config-repo
rabbitmq:
addresses: ${vcap.services.${PREFIX:}rabbitmq.credentials.uri:amqp://${RABBITMQ_HOST:192.168.1.215}:${RABBITMQ_PORT:5672}}
username: alan
password: alan
服務端會自動從指定的git地址獲取配置信息。raabitmq的配置用於通知客戶端應用配置更新。
第二步,配置管理的客戶端
須要在工程中引入spring-cloud-starter-config依賴,使用配置管理服務以後,若是本地的配置文件與配置管理服務器的配置文件有相同的配置項,將優先使用配置管理服務器的配置項。
客戶端的配置文件bookstrap.yml以下:
spring:
application:
name: data
profiles:
active: development
cloud:
config:
uri: http://localhost:8888
rabbitmq:
addresses: amqp://192.168.1.214:5672
username: alan
password: alan
其中,name用來指定應用的名稱和配置文件的名稱,uri設定配置服務服務端的地址和端口,profiles爲使用配置文件名稱的後綴部分,用於綁定不一樣的線上環境。
第三步,使用配置
若是配置文件中有cloud.config.test配置項,能夠這樣使用
@Value("${cloud.config.test:World!}") String msg;
另外,可使用spring-cloud-bus-amqp依賴,經過事件總線的方式,實如今線更新全部客戶端的配置。
在分佈式系統中,可能存在不少應用和服務,各個服務瀆職自主地管理自身的數據。服務與服務之間,須要互相共享一些數據,傳統的方式須要本身編寫一些接口程序,還須要使用複雜的配置來實現,使用Spring Cloud能夠輕易作到這些。
第一步,建立發現服務器
引入spring-cloud-starter-eureka-server依賴,建立一個簡單的主程序便可:
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryApplication.class, args);
}
}
第二步,建立客戶端
引入spring-cloud-starter-eurake依賴,主程序中加入@EnableDiscoveryClient啓用發現服務的客戶端。
配置文件以下:
eureka:
instance:
hostname: discovery
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://192.168.1.221:${server.port}/eureka/
如何在服務間相互調用呢,可使用動態路由、斷路器和故障容錯等功能。
引入spring-cloud-starter-zuul、spring-cloud-starter-hystrix依賴,添加@EnableZuulProxy和@EnableHystrix註解便可。
爲了便於測試,能夠經過共享Rest資源將repository的類直接暴露出來,很神奇吧,以下:
@RepositoryRestResource(collectionResourceRel="users",path="users")
public interface UserRepository extends GraphRepository<User> {
User findByName(@Param("name") String name);
@Query("MATCH (u:User) WHERE u.name =~ ('(?i).*'+{name}+'.*') RETURN u")
Collection<User> findByNameContaining(@Param("name") String name);
}
能夠經過http://localhost/users , http://localhost/users/123 之類的方式訪問。
經過如下3種方式調用其餘服務對外暴露的接口:
以RestTemplate爲例說明一個服務調用data服務的例子:
@Autowired @LoadBalanced
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "getUserFallback")
public User getUserByName(String name) {
Map<String, Object> params = new HashMap<>();
params.put("name", name);
User user = restTemplate.getForObject("http://data/user/findByName?name={name}", User.class, params);
return user;
}
上面例子中使用了@HystrixCommand用於實現斷路器,當一個系統服務忽然出現故障時,會自動阻斷對服務的訪問和調用,轉而調用備用方法。
分佈式服務系統中運行着不少服務,必須有一個管理機制和方法,可以一目瞭然地隨時瞭解各個服務的運行狀況及其健康指數。
使用Spring Cloud的監控服務,能夠實時監控應用的運行狀況。使用很簡單,引入spring-cloud-starter-hystrix-dashboard依賴,建立一個主程序便可:
@SpringBootApplication
@Controller
@EnableHystrixDashboard
public class HystrixApplication{
@RequestMapping("/")
public String home() {
return "forward:/hystrix";
}
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
具體監控指標可參看官網文檔。
使用Spring Cloud開發的微服務,其獨立而又相對隔離的特性,與Docker的理念有殊途同歸之妙,因此使用Docker發佈微服務,可以發揮其最大的優點,而且能夠很是輕易地構建一個高性能和高可用的服務平臺。
Docker能夠很方便地建立和管理鏡像,以及管理已經生成的和正在運行的容器。鏡像是一種文件存儲方式,能夠把許多文件作成一個鏡像文件。容器是鏡像運行的一個實例,運行一個鏡像,就會生成一個容器,容器生成以後,就能夠在容器中管理應用系統了。
Docker的安裝和發佈服務,網上的資料不少,這裏就不贅述了。
另外,可使用其餘一些服務管理工具來構建高性能和高可用的服務平臺。docker-compose工具是Docker容器管理工具集,能夠很方便地用來建立和重建容器、執行啓動和中止容器等管理操做,以及查看整個服務體系的運行狀況和輸出日誌等。使用docker-compose工具,只要一條指令就能啓動整個分佈式服務體系。
經過本篇文章的介紹,你們能夠感覺到Spring Cloud在構建分佈式應用時提供的便捷性,減小了大量的工做量。同時爲咱們考慮了方方面面,加強了系統的穩定性、高性能。
做者把全部代碼都上傳到github,你們能夠直接運行demo深刻了解。
[1] Spring Boot SSO:https://github.com/chenfromsz/spring-boot-sso
[2] 雲應用開發:https://github.com/chenfromsz/spring-boot-cloud