如何用Eureka + Feign搭建分布式微服務(wù)
Eureka
Eureka主要解決了消費(fèi)者對(duì)服務(wù)的記憶問(wèn)題。如果沒(méi)有Eureka,那么消費(fèi)者必須記憶每個(gè)服務(wù)的地址,且一旦服務(wù)提供者宕機(jī)或地址發(fā)生變更,很可能不會(huì)收到通知,導(dǎo)致地址失效。加入Eureka后,只需記住Eureka注冊(cè)中心的地址就能夠找到其它所有服務(wù)。
此外,Eureka能夠接受多個(gè)服務(wù)的注冊(cè),還能夠通過(guò)其它組件的加持直接替代消費(fèi)者進(jìn)行負(fù)載均衡,使消費(fèi)者無(wú)需手動(dòng)選擇服務(wù)。

Feign
Feign是一個(gè)模板化的HTTP客戶端。通過(guò)Feign,可以做到像調(diào)用一個(gè)本地方法一樣請(qǐng)求遠(yuǎn)程服務(wù),無(wú)需編寫繁雜的代碼來(lái)創(chuàng)建HTTP請(qǐng)求。
創(chuàng)建父項(xiàng)目
項(xiàng)目主要分為三個(gè)微服務(wù):服務(wù)提供者、服務(wù)消費(fèi)者、Eureka注冊(cè)中心。為了方便演示,三個(gè)項(xiàng)目都在同一個(gè)主機(jī)上運(yùn)行,且都放在一個(gè)父項(xiàng)目里。
首先在IDEA中創(chuàng)建一個(gè)空項(xiàng)目,然后分別在項(xiàng)目中新建對(duì)應(yīng)的三個(gè)Spring模塊:
- EurekaServer: 注冊(cè)中心,依賴為Eureka Server。
- ServiceProvider: 服務(wù)提供者,依賴為Eureka Discovery Client, Spring Web。
- ServiceConsumer: 服務(wù)消費(fèi)者,依賴為OpenFeign, Eureka Discovery Client, Spring Web。
注冊(cè)中心
服務(wù)提供者通過(guò)向注冊(cè)中心注冊(cè),提供它們的地址供調(diào)用;服務(wù)消費(fèi)者向注冊(cè)中心請(qǐng)求來(lái)獲取可用的服務(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ù)器的注冊(cè)信息 eureka.client.fetch-registry=false # 是否向其它服務(wù)器注冊(cè) eureka.client.register-with-eureka=false # 指定服務(wù)url eureka.client.service-url.defaultZone=http://localhost:1000/eureka
默認(rèn)情況下,Eureka服務(wù)器假定自己是集群的一部分,會(huì)定期向其它Eureka服務(wù)器注冊(cè)自己,并獲取其它服務(wù)器的注冊(cè)信息。由于本項(xiàng)目?jī)H部署一個(gè)Eureka服務(wù)器提供注冊(cè)服務(wù),所以不需要這兩個(gè)動(dòng)作,通過(guò)配置文件的eureka.client.fetch-registry和eureka.client.register-with-eureka兩個(gè)屬性禁用。
eureka.client.service-url包含了每個(gè)zone的名稱和地址。defaultZone是一個(gè)特殊的key,如果客戶端沒(méi)有指定所需的zone,就會(huì)使用這個(gè)默認(rèn)的zone。一般情況下defaultZone的地址就是Eureka服務(wù)器本身。
主類
@SpringBootApplication
@EnableEurekaServer
public class MyEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(MyEurekaServerApplication.class, args);
}
}
要啟動(dòng)Eureka注冊(cè)服務(wù),在原生的Spring Boot啟動(dòng)類上注解@EnableEurekaServer即可。
項(xiàng)目啟動(dòng)后,訪問(wèn)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.
是正常現(xiàn)象。Eureka服務(wù)器默認(rèn)開(kāi)啟了自我保護(hù)模式。由于沒(méi)有收到集群中大部分服務(wù)器的心跳(本項(xiàng)目中就一個(gè)Eureka服務(wù)器,所以該服務(wù)器不會(huì)收到任何心跳,自我保護(hù)模式也沒(méi)有多少影響),Eureka假定出現(xiàn)了網(wǎng)絡(luò)問(wèn)題,開(kāi)啟自我保護(hù)模式。在自我保護(hù)模式下,已經(jīng)注冊(cè)的服務(wù)不會(huì)因?yàn)闆](méi)有收到心跳而被注銷。
如果要關(guān)閉自我保護(hù),可以在配置中設(shè)置如下屬性。
eureka.server.enable-self-preservation=false
服務(wù)提供者
服務(wù)提供者將自己注冊(cè)到注冊(cè)中心。
主要依賴
<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ù)提供者)的實(shí)現(xiàn);spring-boot-starter-web用于將服務(wù)暴露為HTTP端點(diǎn)。
配置文件
# 應(yīng)用端口 server.port=2000 # 應(yīng)用名稱 spring.application.name=service # 注冊(cè)中心地址 eureka.client.service-url.defaultZone=http://localhost:1000/eureka
eureka.client.service-url.defaultZone屬性告訴Eureka客戶端從哪里找到注冊(cè)中心。
主類及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";
}
}
為了展示方便,這些類都寫在同一個(gè)文件中,下同。
這里的Controller提供了一個(gè)簡(jiǎn)單的服務(wù):只要訪問(wèn)/test路徑,就返回一個(gè)字符串test msg。如果有需要,可以同時(shí)啟動(dòng)多個(gè)服務(wù)實(shí)例,模擬服務(wù)器集群提供服務(wù)的情況。
@Slf4j是lombok提供的輔助注解,用于在類中方便地聲明一個(gè)Logger實(shí)例log。
@Value是Spring提供的注解,用于獲取配置文件中的信息。本例中就獲取了之前配置的屬性server.port=2000的值2000,注入到域serverPort中。
啟動(dòng)服務(wù)提供者后,會(huì)自動(dòng)向配置文件中指定的Eureka服務(wù)器進(jìn)行注冊(cè)。此時(shí)訪問(wèn)之前的Eureka服務(wù)器界面,能夠看到已經(jīng)注冊(cè)的服務(wù)信息。這里我分別修改端口號(hào)啟動(dòng)了3個(gè)實(shí)例。

此時(shí)訪問(wèn)服務(wù)提供者所在端口的/test路徑就能夠收到服務(wù)提供的字符串。
客戶端
Feign是一個(gè)模板化的HTTP客戶端。通過(guò)Feign,可以做到像調(diào)用一個(gè)本地方法一樣請(qǐng)求遠(yuǎn)程服務(wù),無(wú)需編寫繁雜的代碼來(lái)創(chuàng)建HTTP請(qǐng)求。
客戶端通過(guò)Feign的加持,可以方便地發(fā)出請(qǐng)求,也可以加入Hystrix的負(fù)載均衡、熔斷降級(jí)等功能。
主要依賴
<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 # 注冊(cè)中心地址 eureka.client.service-url.defaultZone=http://localhost:1000/eureka
同上,eureka.client.service-url.defaultZone屬性指定了客戶端應(yīng)該到哪個(gè)地址尋找注冊(cè)中心。
主類、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請(qǐng)求映射為向服務(wù)的請(qǐng)求。本例中,@FeignClient(value = "service")指定了將調(diào)用映射為向service服務(wù)的請(qǐng)求。而用@GetMapping("/test")則代表每當(dāng)調(diào)用該方法,就向/test路徑請(qǐng)求。綜上,每當(dāng)調(diào)用該方法,該服務(wù)就會(huì)向名為service的服務(wù)的/test路徑發(fā)送HTTP GET請(qǐng)求。這就是Feign的方便之處。
在啟動(dòng)類上需要注解@EnableFeignClients和@EnableDiscoveryClient,啟動(dòng)對(duì)Feign接口的掃描和對(duì)Eureka服務(wù)器的發(fā)現(xiàn)。
類中還寫了一個(gè)MyRestController,用于將對(duì)該服務(wù)的請(qǐng)求映射到方法調(diào)用。調(diào)用鏈為:
- 瀏覽器向Controller發(fā)送HTTP請(qǐng)求
- Controller收到請(qǐng)求后調(diào)用Feign接口中的方法
- Feign將對(duì)方法的調(diào)用映射為對(duì)注冊(cè)中心中服務(wù)的請(qǐng)求并返回
這樣一來(lái),用戶體驗(yàn)到的過(guò)程就是:通過(guò)Feign發(fā)送了一個(gè)請(qǐng)求,然后收到了遠(yuǎn)程服務(wù)器上的信息。
啟動(dòng)客戶端,訪問(wèn)客戶端所在端口的/test路徑,正確收到了服務(wù)提供的字符串。
相關(guān)文章
Java開(kāi)發(fā)環(huán)境jdk 1.8安裝配置方法(Win7 64位系統(tǒng)/windows server 2008)
這篇文章主要介紹了Java開(kāi)發(fā)環(huán)境配置方法(Win7 64位系統(tǒng)/windows server 2008),需要的朋友可以參考下2016-10-10
java WebSocket客戶端斷線重連的實(shí)現(xiàn)方法
在工作中是否會(huì)遇到實(shí)用websocket客戶端連接服務(wù)端的時(shí)候,網(wǎng)絡(luò)波動(dòng),服務(wù)端斷連的情況,本文可以直接使用的斷線重連,感興趣的可以了解一下2021-10-10
帶你重新認(rèn)識(shí)MyBatis的foreach
這篇文章主要介紹了重新認(rèn)識(shí)MyBatis的foreach,本文提出了一種簡(jiǎn)化<foreach>寫法的設(shè)想,更重要的是通過(guò)解決空集時(shí)生成的SQL語(yǔ)法問(wèn)題,更深刻地理解MyBatis的foreach的生成機(jī)制,需要的朋友可以參考下2022-11-11
SpringAMQP消息隊(duì)列(SpringBoot集成RabbitMQ方式)
這篇文章主要介紹了SpringAMQP消息隊(duì)列(SpringBoot集成RabbitMQ方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
詳解微信開(kāi)發(fā)之a(chǎn)ccess_token之坑
access_token分類一是普通access_token,二是網(wǎng)頁(yè)授權(quán)access_token。這篇文章主要介紹了詳解微信開(kāi)發(fā)之a(chǎn)ccess_token之坑,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10

