如何用Eureka + Feign搭建分布式微服務(wù)
Eureka
Eureka主要解決了消費者對服務(wù)的記憶問題。如果沒有Eureka,那么消費者必須記憶每個服務(wù)的地址,且一旦服務(wù)提供者宕機或地址發(fā)生變更,很可能不會收到通知,導(dǎo)致地址失效。加入Eureka后,只需記住Eureka注冊中心的地址就能夠找到其它所有服務(wù)。
此外,Eureka能夠接受多個服務(wù)的注冊,還能夠通過其它組件的加持直接替代消費者進行負載均衡,使消費者無需手動選擇服務(wù)。
Feign
Feign是一個模板化的HTTP客戶端。通過Feign,可以做到像調(diào)用一個本地方法一樣請求遠程服務(wù),無需編寫繁雜的代碼來創(chuàng)建HTTP請求。
創(chuàng)建父項目
項目主要分為三個微服務(wù):服務(wù)提供者、服務(wù)消費者、Eureka注冊中心。為了方便演示,三個項目都在同一個主機上運行,且都放在一個父項目里。
首先在IDEA中創(chuàng)建一個空項目,然后分別在項目中新建對應(yīng)的三個Spring模塊:
- EurekaServer: 注冊中心,依賴為Eureka Server。
- ServiceProvider: 服務(wù)提供者,依賴為Eureka Discovery Client, Spring Web。
- ServiceConsumer: 服務(wù)消費者,依賴為OpenFeign, Eureka Discovery Client, Spring Web。
注冊中心
服務(wù)提供者通過向注冊中心注冊,提供它們的地址供調(diào)用;服務(wù)消費者向注冊中心請求來獲取可用的服務(wù)。
主要依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
配置文件
# 端口 server.port=1000 # 指定應(yīng)用名稱 spring.application.name=server # 是否拉取其它服務(wù)器的注冊信息 eureka.client.fetch-registry=false # 是否向其它服務(wù)器注冊 eureka.client.register-with-eureka=false # 指定服務(wù)url eureka.client.service-url.defaultZone=http://localhost:1000/eureka
默認情況下,Eureka服務(wù)器假定自己是集群的一部分,會定期向其它Eureka服務(wù)器注冊自己,并獲取其它服務(wù)器的注冊信息。由于本項目僅部署一個Eureka服務(wù)器提供注冊服務(wù),所以不需要這兩個動作,通過配置文件的eureka.client.fetch-registry和eureka.client.register-with-eureka兩個屬性禁用。
eureka.client.service-url包含了每個zone的名稱和地址。defaultZone是一個特殊的key,如果客戶端沒有指定所需的zone,就會使用這個默認的zone。一般情況下defaultZone的地址就是Eureka服務(wù)器本身。
主類
@SpringBootApplication @EnableEurekaServer public class MyEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(MyEurekaServerApplication.class, args); } }
要啟動Eureka注冊服務(wù),在原生的Spring Boot啟動類上注解@EnableEurekaServer即可。
項目啟動后,訪問localhost:1000就能看到Eureka提供的界面了。如果在界面上看到警告
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
是正?,F(xiàn)象。Eureka服務(wù)器默認開啟了自我保護模式。由于沒有收到集群中大部分服務(wù)器的心跳(本項目中就一個Eureka服務(wù)器,所以該服務(wù)器不會收到任何心跳,自我保護模式也沒有多少影響),Eureka假定出現(xiàn)了網(wǎng)絡(luò)問題,開啟自我保護模式。在自我保護模式下,已經(jīng)注冊的服務(wù)不會因為沒有收到心跳而被注銷。
如果要關(guān)閉自我保護,可以在配置中設(shè)置如下屬性。
eureka.server.enable-self-preservation=false
服務(wù)提供者
服務(wù)提供者將自己注冊到注冊中心。
主要依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
spring-cloud-starter-netflix-eureka-client依賴包含了Eureka客戶端(即服務(wù)提供者)的實現(xiàn);spring-boot-starter-web用于將服務(wù)暴露為HTTP端點。
配置文件
# 應(yīng)用端口 server.port=2000 # 應(yīng)用名稱 spring.application.name=service # 注冊中心地址 eureka.client.service-url.defaultZone=http://localhost:1000/eureka
eureka.client.service-url.defaultZone屬性告訴Eureka客戶端從哪里找到注冊中心。
主類及Controller
@SpringBootApplication public class MyEurekaServiceApplication { public static void main(String[] args) { SpringApplication.run(MyEurekaServiceApplication.class, args); } } @RestController @RequestMapping("/test") @Slf4j class MyController { @Value("${server.port}") private int serverPort; @GetMapping public String getHandler() { log.info("##############received call, port: " + this.serverPort); return "test msg"; } }
為了展示方便,這些類都寫在同一個文件中,下同。
這里的Controller提供了一個簡單的服務(wù):只要訪問/test路徑,就返回一個字符串test msg。如果有需要,可以同時啟動多個服務(wù)實例,模擬服務(wù)器集群提供服務(wù)的情況。
@Slf4j是lombok提供的輔助注解,用于在類中方便地聲明一個Logger實例log。
@Value是Spring提供的注解,用于獲取配置文件中的信息。本例中就獲取了之前配置的屬性server.port=2000的值2000,注入到域serverPort中。
啟動服務(wù)提供者后,會自動向配置文件中指定的Eureka服務(wù)器進行注冊。此時訪問之前的Eureka服務(wù)器界面,能夠看到已經(jīng)注冊的服務(wù)信息。這里我分別修改端口號啟動了3個實例。
此時訪問服務(wù)提供者所在端口的/test路徑就能夠收到服務(wù)提供的字符串。
客戶端
Feign是一個模板化的HTTP客戶端。通過Feign,可以做到像調(diào)用一個本地方法一樣請求遠程服務(wù),無需編寫繁雜的代碼來創(chuàng)建HTTP請求。
客戶端通過Feign的加持,可以方便地發(fā)出請求,也可以加入Hystrix的負載均衡、熔斷降級等功能。
主要依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
配置文件
# 應(yīng)用端口 server.port=3000 # 應(yīng)用名稱 spring.application.name=feignClient # 注冊中心地址 eureka.client.service-url.defaultZone=http://localhost:1000/eureka
同上,eureka.client.service-url.defaultZone屬性指定了客戶端應(yīng)該到哪個地址尋找注冊中心。
主類、Controller及Feign映射
@FeignClient(value = "service") interface FeignController { @GetMapping("/test") public String getHandler(); } @SpringBootApplication @EnableFeignClients @EnableDiscoveryClient public class MyFeignClientApplication { public static void main(String[] args) { SpringApplication.run(MyFeignClientApplication.class, args); } } @RestController @RequestMapping("/test") class MyRestController { @Autowired FeignController feignController; @GetMapping public String getHandler() { return feignController.getHandler(); } }
類中的接口FeignController將發(fā)往該端口的HTTP請求映射為向服務(wù)的請求。本例中,@FeignClient(value = "service")指定了將調(diào)用映射為向service服務(wù)的請求。而用@GetMapping("/test")則代表每當(dāng)調(diào)用該方法,就向/test路徑請求。綜上,每當(dāng)調(diào)用該方法,該服務(wù)就會向名為service的服務(wù)的/test路徑發(fā)送HTTP GET請求。這就是Feign的方便之處。
在啟動類上需要注解@EnableFeignClients和@EnableDiscoveryClient,啟動對Feign接口的掃描和對Eureka服務(wù)器的發(fā)現(xiàn)。
類中還寫了一個MyRestController,用于將對該服務(wù)的請求映射到方法調(diào)用。調(diào)用鏈為:
- 瀏覽器向Controller發(fā)送HTTP請求
- Controller收到請求后調(diào)用Feign接口中的方法
- Feign將對方法的調(diào)用映射為對注冊中心中服務(wù)的請求并返回
這樣一來,用戶體驗到的過程就是:通過Feign發(fā)送了一個請求,然后收到了遠程服務(wù)器上的信息。
啟動客戶端,訪問客戶端所在端口的/test路徑,正確收到了服務(wù)提供的字符串。
相關(guān)文章
Java java.lang.InstantiationException異常案例詳解
這篇文章主要介紹了Java java.lang.InstantiationException異常案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08Java Map 按key排序和按Value排序的實現(xiàn)方法
下面小編就為大家?guī)硪黄狫ava Map 按key排序和按Value排序的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08關(guān)于MyBatis Plus中使用or和and問題
這篇文章主要介紹了關(guān)于MyBatis Plus中使用or和and問題,需要的朋友可以參考下2020-12-12