Spring Cloud Eureka作为一个服务注册与发现组件,是基于Netflix Eureka的二次封装,是Spring Cloud的重要组成部分
单机版Eureka
搭建Eureka注册中心
POM依赖
在Eureka中具体包含两个组件:Eureka Server、Eureka Client。前者即为注册中心;后者则用于完成服务向注册中心的注册与发现。故这里先建立一个SpringBoot项目,用于作为Eureka Server。其POM中相关依赖如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <dependencyManagement> <dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency>
</dependencies> </dependencyManagement>
<dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
</dependencies>
|
配置文件
为了便于后续演示,我们在hosts文件中先添加映射,如下所示
配置文件application.yml如下所示。这里我们不需要注册中心对自身进行注册,故register-with-eureka、fetch-registry设为false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| server: port: 7001
spring: application: name: eureka server
eureka: instance: hostname: eureka7001.com client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://localhost:7001/eureka/
|
Java实现
作为Eureka Server而言,Java代码比较简单。我们只需提供一个SpringBoot启动类即可。值得一提的是,需要在该启动类上添加 @EnableEurekaServer 注解
1 2 3 4 5 6 7
| @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
|
搭建服务提供者
POM依赖
同样再次建立一个SpringBoot项目Payment用于对外提供服务。由于该服务需要注册到Eureka中,故需要向其中引入Eureka Client依赖。如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <dependencyManagement> <dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency>
</dependencies> </dependencyManagement>
<dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
</dependencies>
|
配置文件
在配置文件中,我们定义了payment服务的两个实例,分别使用8001、8002端口。在启动时中通过设置不同的spring.profiles.active配置,即可启动两个使用不同端口的payment服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| spring: application: name: payment profiles: active: payment1
eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka
---
spring: profiles: payment1
server: port: 8001
eureka: instance: instance-id: payment-8001
---
spring: profiles: payment2
server: port: 8002
eureka: instance: instance-id: payment-8002
|
Java实现
为便于测试,我们提供一个Controller,如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @RestController @RequestMapping("pay") public class PaymentController {
@Value("${server.port}") private String serverPort;
@GetMapping("/getServerPort") public String getServerPort() { String msg = "[Payment Service]: Port: " + serverPort; return msg; }
@GetMapping("/hello") public String hello(@RequestParam String name) { String msg = "[Payment Service-"+ serverPort +"]: " + name; return msg; }
}
|
同时在启动类上添加 @EnableEurekaClient 注解
1 2 3 4 5 6 7
| @SpringBootApplication @EnableEurekaClient public class PaymentApplication { public static void main(String[] args) { SpringApplication.run(PaymentApplication.class, args); } }
|
搭建服务消费者
POM依赖
类似地,建立SpringBoot项目Order作为服务消费者。同理该项目也需要引入Eureka Client依赖。如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <dependencyManagement> <dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency>
</dependencies> </dependencyManagement>
<dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
</dependencies>
|
配置文件
一般地,微服务中一个服务既是提供者也是消费者,故我们也将该服务注册到Eureka中。配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| server: port: 80
spring: application: name: order
eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka instance: instance-id: order-80
|
Java实现
首先声明创建RestTemplate实例。一个是普通的RestTemplate实例,一个则是添加了 @LoadBalanced 注解的RestTemplate实例。前者可进行基于IP、Port服务调用;后者由于添加了 @LoadBalanced 注解,其一方面可进行基于服务名的服务调用,另一方面支持负载均衡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Configuration public class RestTemplateConfig {
@Bean public RestTemplate restTemplate1() { return new RestTemplate(); }
@Bean @LoadBalanced public RestTemplate restTemplate2() { return new RestTemplate(); }
}
|
然后通过Controller调用Payment服务接口。下面展现了 传统地基于IP、Port信息 和 基于服务名 两种形式的服务调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @RestController @RequestMapping("order") public class OrderController {
@Qualifier("restTemplate1") @Autowired private RestTemplate restTemplate1;
@Qualifier("restTemplate2") @Autowired private RestTemplate restTemplate2;
private static final String PAYMENT_URL_1 = "http://localhost:8001";
private static final String PAYMENT_URL_2 = "http://PAYMENT";
@GetMapping("/test1") public String test1(@RequestParam String name) { String msg = restTemplate1.getForObject(PAYMENT_URL_1 +"/pay/hello?name={1}", String.class, name); String result = "[Order Service #test1]: " + msg; return result; }
@GetMapping("/test2") public String test2(@RequestParam String name) { String msg = restTemplate2.getForObject(PAYMENT_URL_2 +"/pay/hello?name={1}", String.class, name); String result = "[Order Service #test2]: " + msg; return result; } }
|
最后,在启动类上添加 @EnableEurekaClient 注解
1 2 3 4 5 6 7
| @SpringBootApplication @EnableEurekaClient public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
|
测试
启动Eureka Server、Payment、Order三个服务。其中,Payment服务启动了两个实例,如下所示
打开 http://localhost:7001 ,进入Eureka Server的Web页面,可以看到Payment、Order服务都已经被成功注册到Eureka当中。其中Payment服务下存在两个实例
现在我们通过Order服务来调用Payment服务的接口,测试结果如下,符合预期。与此同时,红框结果同时表明实现了负载均衡
集群版Eureka环境
Eureka集群环境搭建也比较简单,只是相关的配置文件发生变化。这里就Server、Client侧分别说明
Eureka Server配置
在Eureka集群环境中,各实例的 eureka.client.service-url.defaultZone 不再是指向自己,而是指向集群下的其它实例。下面即是一个包含三实例的Eureka集群配置,如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| spring: application: name: eureka server profiles: active: eurekaServer1
---
spring: profiles: eurekaServer1
server: port: 7001
eureka: instance: hostname: eureka7001.com client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/
---
spring: profiles: eurekaServer2
server: port: 7002
eureka: instance: hostname: eureka7002.com client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7003.com:7003/eureka/ ---
spring: profiles: eurekaServer3
server: port: 7003
eureka: instance: hostname: eureka7003.com client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
|
启动该集群环境后,进入任一一个Eureka实例的Web页面,即可看到整个集群环境已经建立完毕。如下所示
Eureka Client配置
Eureka Client的配置就比较简单,我们以payment服务为例。只需将 eureka.client.service-url.defaultZone 配置项指向Eureka集群的各实例即可,如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| spring: application: name: payment profiles: active: payment1 eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
|
Note
- IDEA下启动某个服务的多实例,需要先勾选 Allow parallel 配置
参考文献
- Spring微服务实战 John Carnell著