本例中我们在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