一個(gè)使用Spring, Spring Boot 和 Spring Cloud設(shè)置微服務(wù)系統(tǒng)的簡單示例办龄。
微服務(wù)允許從許多協(xié)作組件構(gòu)建大型系統(tǒng)烘绽。它在流程級別執(zhí)行Spring在組件級別執(zhí)行的操作:松散耦合的流程而不是松散耦合的組件。
例如,設(shè)想一個(gè)在線商店英融,為用戶帳戶盏檐、產(chǎn)品目錄訂單處理和購物車提供單獨(dú)的微服務(wù):
不可避免地,要構(gòu)建這樣一個(gè)系統(tǒng)驶悟,必須設(shè)置和配置許多移動(dòng)部件胡野。如何讓它們協(xié)同工作并不明顯——你需要很好地熟悉Spring Boot,因?yàn)镾pring Cloud充分利用了它痕鳍,需要幾個(gè)Netflix或其他OSS項(xiàng)目硫豆,當(dāng)然,還有一些Spring配置“魔力”!
在本文中,我旨在通過逐步構(gòu)建最簡單的系統(tǒng)來闡明事物是如何工作的耘眨。因此昼榛,我將只實(shí)現(xiàn)大系統(tǒng)的一小部分—用戶帳戶服務(wù)。
Web應(yīng)用程序?qū)⑹褂胷estful api向帳戶服務(wù)microservice發(fā)出請求剔难。我們還需要添加一個(gè)發(fā)現(xiàn)服務(wù)胆屿,以便其他進(jìn)程能夠找到彼此。
此應(yīng)用程序的代碼如下:http://github.com/paulc4/microservices-demo
對其工作原理的描述非常詳細(xì)偶宫。不耐煩的讀者可能更喜歡簡單地看代碼非迹。注意,它在一個(gè)項(xiàng)目中包含三個(gè)微服務(wù)纯趋。
好吧憎兽,我們開始吧…
服務(wù)注冊
當(dāng)多個(gè)進(jìn)程協(xié)同工作時(shí),它們需要找到彼此吵冒。如果您曾經(jīng)使用過Java的RMI機(jī)制纯命,您可能還記得它依賴于一個(gè)中央注冊表,這樣RMI進(jìn)程就可以找到彼此痹栖。微服務(wù)也有同樣的要求亿汞。
Netflix的開發(fā)人員在構(gòu)建系統(tǒng)時(shí)遇到了這個(gè)問題,他們創(chuàng)建了一個(gè)名為Eureka的注冊服務(wù)器(希臘語為“我找到了”)揪阿。對我們來說幸運(yùn)的是疗我,他們使他們的發(fā)現(xiàn)服務(wù)器開源,而且Spring已經(jīng)并入Spring Cloud南捂,這使得運(yùn)行Eureka服務(wù)器更加容易吴裤。下面是完整的discovery server應(yīng)用程序:
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistrationServer {
public static void main(String[] args) {
// Tell Boot to look for registration-server.yml
System.setProperty("spring.config.name", "registration-server");
SpringApplication.run(ServiceRegistrationServer.class, args);
}
}
就這么簡單!
SpringCloud構(gòu)建在SpringBoot上溺健,并使用父級和啟動(dòng)POM麦牺。POM的重要部分包括:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<!-- Setup Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<!-- Setup Spring MVC & REST, use Embedded Tomcat -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!-- Spring Cloud starter -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<!-- Eureka for service registration -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- Spring Cloud dependencies -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
這個(gè)POM已經(jīng)改變,因?yàn)槲易畛鯇懙奈恼率褂胹pringboot作為其父代矿瘦,而不是springcloud枕面。Spring云依賴關(guān)系是通過依賴關(guān)系管理部分提供的。
github代碼中還包含一個(gè)示例gradle構(gòu)建文件缚去。
默認(rèn)情況下潮秘,Spring引導(dǎo)應(yīng)用程序?qū)ふ覒?yīng)用程序?qū)傩曰蛘遖pplication.yml配置文件。通過設(shè)置spring.config.name屬性易结,我們可以告訴SpringBoot查找不同的文件—如果您在同一個(gè)項(xiàng)目中有多個(gè)SpringBoot應(yīng)用程序枕荞,這很有用—我很快就會這么做柜候。
此應(yīng)用程序?qū)ふ襯egistration-server.properties或registration-server.yml. 以下是注冊的相關(guān)registration-server.yml:
# Configure this Discovery Server
eureka:
instance:
hostname: localhost
client: # Not a client, don't register with yourself (unless running
# multiple discovery servers for redundancy)
registerWithEureka: false
fetchRegistry: false
server:
port: 1111 # HTTP (Tomcat) port
默認(rèn)情況下,Eureka在端口8761上運(yùn)行躏精,但這里我們將使用端口1111渣刷。另外,通過在進(jìn)程中包含注冊碼矗烛,我可能是一個(gè)服務(wù)器或客戶機(jī)辅柴。配置指定我不是客戶機(jī),并停止服務(wù)器進(jìn)程嘗試向自身注冊瞭吃。
現(xiàn)在嘗試運(yùn)行RegistrationServer(請參閱下面的運(yùn)行應(yīng)用程序的幫助)碌嘀。您可以在此處打開Eureka儀表板:http://localhost:1111,顯示應(yīng)用程序的部分將為空歪架。
從現(xiàn)在起股冗,我們將提到發(fā)現(xiàn)服務(wù)器,因?yàn)樗赡苁荅ureka或Consul和蚪。
Spring Cloud還支持Consul作為Eureka的替代品止状。您可以使用腳本啟動(dòng)consur代理(它的注冊服務(wù)器),然后客戶機(jī)使用它來查找他們的微服務(wù)攒霹。
創(chuàng)建微服務(wù):帳戶服務(wù)
微服務(wù)是處理定義良好的需求的獨(dú)立流程怯疤。
[圖片上傳失敗...(image-659c2-1614603159869)]
在使用Spring配置應(yīng)用程序時(shí),我們強(qiáng)調(diào)松耦合和緊密內(nèi)聚剔蹋,這不是新概念(Larry Constantine在20世紀(jì)60年代末首次定義了這些概念)旅薄,但現(xiàn)在我們將它們應(yīng)用于交互組件(Springbeans),而不是交互過程泣崩。
在這個(gè)例子中,我有一個(gè)簡單的帳戶管理微服務(wù)洛口,它使用Spring數(shù)據(jù)實(shí)現(xiàn)jpaccount repository矫付,Spring REST提供一個(gè)RESTful接口來訪問帳戶信息。在大多數(shù)方面第焰,這是一個(gè)簡單的Spring Boot application买优。
它的特殊之處在于它在啟動(dòng)時(shí)向發(fā)現(xiàn)服務(wù)器注冊。以下是Spring Boot啟動(dòng)類:
@EnableAutoConfiguration
@EnableDiscoveryClient
@Import(AccountsWebApplication.class)
public class AccountsServer {
@Autowired
AccountRepository accountRepository;
public static void main(String[] args) {
// Will configure using accounts-server.yml
System.setProperty("spring.config.name", "accounts-server");
SpringApplication.run(AccountsServer.class, args);
}
}
注釋完成了以下工作:
@EnableAutoConfiguration 將其定義為Spring引導(dǎo)應(yīng)用程序挺举。
@EnableDiscoveryClient 這將啟用服務(wù)注冊和發(fā)現(xiàn)杀赢。在本例中,此進(jìn)程使用其應(yīng)用程序名稱(見下文)向discovery server服務(wù)注冊自己湘纵。
@Import(AccountsWebApplication.class)-這個(gè)Java配置類設(shè)置其他所有內(nèi)容(請參閱下面的詳細(xì)信息)脂崔。
使這成為一項(xiàng)微服務(wù)的是通過@EnableDiscoveryClient向發(fā)現(xiàn)服務(wù)器注冊,其YML配置完成了設(shè)置:
# Spring properties
spring:
application:
name: accounts-service
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
# HTTP Server
server:
port: 2222 # HTTP (Tomcat) port
請注意梧喷,此文件
1. 將應(yīng)用程序名稱設(shè)置為accounts-service砌左。此服務(wù)使用此名稱注冊脖咐,也可以使用此名稱訪問-請參閱下面的。
2. 指定要偵聽的自定義端口(2222)汇歹。我所有的進(jìn)程都在使用Tomcat屁擅,它們不能都監(jiān)聽端口8080。
3. Eureka服務(wù)進(jìn)程的URL-來自上一節(jié)产弹。
現(xiàn)在運(yùn)行AccountsService應(yīng)用程序并讓它完成初始化派歌。刷新儀表板http://localhost:1111并且您應(yīng)該看到“應(yīng)用程序”下列出的ACCOUNTS-SERVICE。注冊最多需要30秒(默認(rèn)情況下)痰哨,所以請耐心檢查RegistrationService的日志輸出
欲了解更多詳情作谭,請點(diǎn)擊此處:http://localhost:1111/eureka/apps/您應(yīng)該看到如下內(nèi)容:
<applications>
<versions__delta>1</versions__delta>
<apps__hashcode>UP_1_</apps__hashcode>
<application>
<name>ACCOUNTS-SERVICE</name>
<instance>
<hostName>autgchapmp1m1.corp.emc.com</hostName>
<app>ACCOUNTS-SERVICE</app>
<ipAddr>172.16.84.1</ipAddr><status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">3344</port>
<securePort enabled="false">443</securePort>
...
</instance>
</application>
</applications>
警告:不要嘗試使用Eclipse/STS的內(nèi)部web查看器顯示XML輸出稽物,因?yàn)樗荒苓@樣做。改用你最喜歡的網(wǎng)絡(luò)瀏覽器折欠。
或者轉(zhuǎn)到http://localhost:1111/eureka/apps/ACCOUNTS-SERVICE贝或,只需查看AccountsService的詳細(xì)信息-如果未注冊,您將獲得404锐秦。
配置選項(xiàng)
注冊時(shí)間:注冊最多需要30秒咪奖,因?yàn)檫@是默認(rèn)的客戶端刷新時(shí)間。您可以通過設(shè)置eureka.instance.leaseRenewalIntervalInSeconds=秒屬性設(shè)置為較小的數(shù)字(在演示應(yīng)用程序中酱床,我已將其設(shè)置為5)羊赵。在生產(chǎn)中不建議這樣做。
eureka:
instance:
leaseRenewalIntervalInSeconds: 5 # DO NOT DO THIS IN PRODUCTION
注冊Id:進(jìn)程(微服務(wù))使用唯一的Id向發(fā)現(xiàn)服務(wù)注冊扇谣。如果另一個(gè)進(jìn)程使用相同的Id注冊昧捷,它將被視為重新啟動(dòng)(例如某種故障轉(zhuǎn)移或恢復(fù)),第一個(gè)進(jìn)程注冊將被丟棄罐寨。這為我們提供了所需的容錯(cuò)系統(tǒng)靡挥。
為了運(yùn)行同一進(jìn)程的多個(gè)實(shí)例(為了負(fù)載平衡和恢復(fù)能力),它們需要用一個(gè)唯一的id注冊鸯绿。
在Angel release train下跋破,客戶機(jī)用于向發(fā)現(xiàn)服務(wù)器注冊的實(shí)例id是從客戶機(jī)的服務(wù)名稱(與Spring應(yīng)用程序名稱相同)以及客戶機(jī)的主機(jī)名稱派生而來的。因此瓶蝴,在同一主機(jī)上運(yùn)行的相同進(jìn)程將具有相同的id毒返,因此只有一個(gè)進(jìn)程可以注冊。
幸運(yùn)的是舷手,您可以通過客戶端的Eureka元數(shù)據(jù)映射手動(dòng)設(shè)置id屬性拧簸,如下所示:
eureka:
instance:
metadataMap:
instanceId: ${spring.application.name}:${spring.application.instance_id:${server.port}}
自從Brixton發(fā)布train以來,這是默認(rèn)的聚霜。那它做什么呢狡恬?
我們正在將instanceId設(shè)置為application-name:instance_id珠叔,但如果未定義instance_id,則將改用application-name::server-port弟劲。請注意spring.application.instance_id僅在使用CloudFoundry時(shí)設(shè)置祷安,但它方便地為同一應(yīng)用程序的每個(gè)實(shí)例提供唯一的id號。在其他地方運(yùn)行時(shí)兔乞,我們可以使用服務(wù)器端口執(zhí)行類似的操作(因?yàn)橥慌_機(jī)器上的不同實(shí)例必須偵聽不同的端口)汇鞭。你經(jīng)常看到的另一個(gè)例子是{spring.application.instance_id:${random.value}}但我個(gè)人發(fā)現(xiàn)庸追,使用端口號可以很容易地識別每個(gè)實(shí)例—隨機(jī)值只是長字符串霍骄,沒有任何意義。
注意:語法{y}}是{x} : ${y}淡溯。
自從Brixton發(fā)布以來读整,它還有一個(gè)專門的屬性:
eureka:
instance:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
訪問微服務(wù):Web服務(wù)
為了使用RESTful服務(wù),Spring提供了RestTemplate類咱娶。這允許您向RESTful服務(wù)器發(fā)送HTTP請求米间,并以多種格式獲取數(shù)據(jù),例如JSON和XML膘侮。
可以使用哪種格式取決于類路徑上是否存在marshaling類—例如屈糊,JAXB總是被檢測到,因?yàn)樗荍ava的標(biāo)準(zhǔn)部分琼了。如果類路徑中存在Jackson jar逻锐,則支持JSON。
微服務(wù)(discovery)客戶機(jī)可以使用restemplate雕薪,Spring會自動(dòng)將其配置為支持微服務(wù)(稍后會有更多)昧诱。
注意:Accounts微服務(wù)提供了一個(gè)基于HTTP的RESTful接口,但是可以使用任何合適的協(xié)議蹦哼。使用AMQP或JMS的消息傳遞是一個(gè)明顯的替代方案(在這種情況下鳄哭,不再需要發(fā)現(xiàn)服務(wù)器—相反,進(jìn)程需要知道要與之交談的隊(duì)列的名稱纲熏,可以考慮為此使用Spring云配置服務(wù)器)。
以上就是有關(guān)使用Spring搭建微服務(wù)框架的學(xué)習(xí)筆記锄俄,希望可以對大家的學(xué)習(xí)有幫助局劲,喜歡的小伙伴可以幫忙轉(zhuǎn)發(fā)+關(guān)注,感謝大家奶赠!LZ后期會不定時(shí)更新干貨的S闾睢!毅戈!