本例中我們在spring boot cloud架構下用,eureka和feign搭建一個簡單的基于微服務的分布式系統。該為服務系統隻有四個子產品,即四個微服務:
兩個生産子產品ProviderModule和ProviderModule2,模拟服務提供方,比如訂單服務;
一個調用子產品InvokeModule,調用兩個生産子產品,模拟服務消費。
一個注冊服務子產品eurekaServerModule,用來提供微服務的注冊和發現。
系統服務注冊與發現用eureka,服務遠端調用feign,并且feign內建有負載均衡功能。具體實作步驟和代碼如下。
項目名稱是service-eureka-feign,下面有四個子產品(子項目,)結構如下圖所示

主項目的pom.xml如下
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>service-eureka-feign</artifactId>
<version>0.1.0</version>
<packaging>pom</packaging>
<modules>
<module>InvokerModule</module>
<module>ProviderModule</module>
<module>ProviderModule2</module>
<module>eurekaServerModule</module>
</modules>
</project>
(1)eurekaServerModule子產品
pom.xml中關鍵的依賴包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
application.properties配置檔案
server.port=8761
spring.application.name=server
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
啟動類EurekaServerApplication
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
(2)服務提供子產品ProviderModule
pom.xml
<groupId>my.com</groupId>
<artifactId>ProviderModule</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ProviderModule</name>
<description>ProviderModule</description>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置檔案 application.properties
server.port=9000
spring.application.name=provider
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
啟動類ProviderApp
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
}
服務提供類ProviderController ,用controller來模型提供的接口,服務提供方法是showProvider()
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
class ProviderController {
@RequestMapping("/list/provider")
public String showProvider(@RequestParam String name) {
System.out.println("from provider port 9000");
return "hello "+name + " from provider ";
}
@RequestMapping("/list/test/{name}")
public String showTest(@PathVariable String name) {
return "hello 2 "+name;
}
}
(3) 服務提供子產品ProviderModule2
該子產品與ProviderModule的java代碼非常相同,隻有配置檔案和pom.xml不一樣
pom.xml
<groupId>my.com</groupId>
<artifactId>ProviderModule2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ProviderModule2</name>
<description>ProviderModule2</description>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置檔案 application.properties
server.port=9002
spring.application.name=provider #與第一個服務提供子產品一樣的名字,後面友善feign統一調用
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
服務提供類ProviderController,注意該方法與ProviderModule中的ProviderController方法非常相似,一般來說要提高類似的功能,比如訂購車票服務,隻是涉及通路的資源不一樣,比如通路不同的資料庫等。
@RestController
class ProviderController {
@RequestMapping("/list/provider")
public String showProvider(@RequestParam String name) {
System.out.println("from provider2 port 9002");
return "hello "+name + " from provider2 ";
}
@RequestMapping("/list/test/{name}")
public String showTest(@PathVariable String name) {
return "hello 2 "+name;
}
}
(4)服務消費者子產品InvokeModule
pom.xml
<groupId>com.example</groupId>
<artifactId>InvokeModule</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>InvokeModule</name>
<description>InvokeModule</description>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置檔案 application.properties
server.port=8000
spring.application.name=invoker
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
啟動類InvokerAPP
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class InvokerAPP {
public static void main(String[] args) {
SpringApplication.run(InvokerAPP.class, args);
}
}
遠端服務調用接口(feign調用),調用的注冊在eureka中的服務名稱為“PROVIDER” ,有同名的兩個服務提供者。
@FeignClient("PROVIDER") //開啟Feign用戶端,PROVIDER是兩個ProviderModule和ProviderModule2微服務的serviceId
public interface FeignService {
//對應要調用的ProviderModule和ProviderModule2微服務控制層請求方法
@RequestMapping("/list/provider")
String getUser(@RequestParam String name);
}
使用遠端接口調用,用controller來模拟調用feign遠端調用接口 。用循環模拟調用了10次。
@RestController
public class InvokerController {
@Autowired
private FeignService feignService;
@RequestMapping("/feign")
public String testInvoke(@RequestParam String name) {
String result = "";
//調用10次使用者微服務
for (int i = 1; i <= 10; i++) {
//調用定義Feign用戶端方法
System.out.println(i);
result = feignService.getUser("invoker "+name);
}
return result;
}
}
開始測試:
分别啟動eurekaServerModule,ProviderModule,ProviderModule2和InvokerModule四個微服務。在浏覽器輸入eureka伺服器位址:http://localhost:8761/,得到如下的結果。
上圖中eureka伺服器中有兩個同名的provider服務。
在浏覽器中輸入調用位址http://localhost:8000/feign?name=張三,有如下的輸出
上圖輸出的是傳回到浏覽器的結果
ProviderModule子產品的控制台輸出
ProviderModule2子產品的控制台輸出
在上面兩個圖中可以看出, InvokerModule用同一名稱PROVIDER總共調用了10次服務,這10次服務分别評價配置設定到了兩個微服務提供子產品,起到了負載均衡作用。
完整的項目代碼位址:連結:https://pan.baidu.com/s/1UzoktQkFieMQ4Tm-tydhkA
提取碼:72sy