SpringCloud 笔记2

前记

上一章介绍完基本概念,这章将开始搭建服务。

主要从注册中心、发布服务、消费服务这几个方面开始。

Eureka Server 服务注册中心

为了方便搭建,这里直接使用 Idea 中的 Spring Initializr 构建。

流程:

  1. 先创建 Maven 主工程。
  2. 然后创建2个 Module,一个作为 server,一个作为 client。

这里先在 server 中进行操作。

添加依赖:

1
2
3
4
5
6
7
8
<dependencies>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

</dependencies>

添加注解 @EnableEurekaServer,使得 SpringBoot 应用成为服务注册中心:

1
2
3
4
5
6
7
8
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}

application.properties 配置文件中写入:

1
2
3
4
5
6
7
8
9
10
11
12
# eureka server端口
server.port=7000

# eureka server的主机名
eureka.instance.hostname=localhost

# 当前服务不需要到eureka server上注册(默认情况下server也是一个client)
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

# 供客户端注册的地址
eureka.client.service-url.defaultZone=http://localhost:${server.port}/eureka/

启动工程,打开 http://localhost:7000/ 即可进入 Eureka Server。

Eureka Server

可以看到标红的地方显示没有发现任何服务。

Eureka Client 服务提供

现在创建一个可以提供计算服务的客户端,添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>

<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>

</dependencies>

添加注解 @EnableDiscoveryClient 声明该应用是一个 Eureka Client。

1
2
3
4
5
6
7
8
@EnableDiscoveryClient
@SpringBootApplication
public class ComputeServiceApplication {

public static void main(String[] args) {
SpringApplication.run(ComputeServiceApplication.class, args);
}
}

application.properties 配置文件中写入:

1
2
3
4
5
6
7
# eureka client端口
server.port=8000
# 消费者将通过该名称调用所提供的服务
spring.application.name=computeService

# 在server的上注册,这里在可以多个server注册
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/

实现一个 RESTFul API 风格的 /add 接口,提供加法服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RestController
public class ComputeController {

private final Logger logger = LoggerFactory.getLogger(ComputeController.class);

@Resource
private EurekaInstanceConfig eurekaInstanceConfig;

@Value("${server.port}")
private Integer serverPort;

@GetMapping("/add")
public String add(@RequestParam Integer a, @RequestParam Integer b) {
Integer after = a + b;
logger.info("/add, instanceId:{} , host:{} , result:{}",
eurekaInstanceConfig.getInstanceId(), eurekaInstanceConfig.getHostName(false), after);
return String.format("Result: %d, from port: %d", after, serverPort);
}
}

启动客户端,可以看到已经在 server 上注册:

已经注册服务

通过启动多个实例达到集群的目的(如何启动可以看这篇[文章]https://blog.csdn.net/forezp/article/details/76408139))

已经注册多个计算服务

服务消费

上面已经完成了计算服务的注册,接下来是消费其提供出来的接口。

SpringCloud 有两种服务调用方式:

  • Ribbon + RestTemplate
  • Feign

Ribbon + RestTemplate

同样,添加一个服务消费的 Module,命名为 ribbonConsumer。

依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependencies>

<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-netflix-ribbon</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

添加注解 @EnableDiscoveryClient 使得消费者可以发现服务;添加 RestTemplate Bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}

@Bean
// 开启负载均衡
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}

application.properties 配置文件中写入:

1
2
3
4
5
6
7
# 消费者端口
server.port=9000
# 消费者名称
spring.application.name=ribbonConsumer

# 和客户端一样,这里可以在多个server注册
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/

创建接口,去消费 COMPUTESERVICE 提供的 add 服务:

1
2
3
4
5
6
7
8
9
@Service
public class RibbonComputeService {
@Resource
private RestTemplate restTemplate;

public String add(Integer a, Integer b) {
return restTemplate.getForEntity("http://COMPUTESERVICE/add?a=" + a + "&b=" + b, String.class).getBody();
}
}

控制器:

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class RibbonConsumerController {

@Resource
private RibbonComputeService computeService;

@GetMapping("/add")
public String add(@RequestParam Integer a, @RequestParam Integer b) {
return computeService.add(a, b);
}
}

然后启动消费者,可以看到都注册上了:

Ribbon

访问多几次消费者的网址 http://localhost:9000/add:

1
2
3
4
5
6
7
8
9
10
11
$ curl http://localhost:9000/add\?a\=1\&b\=66
Result: 67, from port: 8001

$ curl http://localhost:9000/add\?a\=1\&b\=45
Result: 46, from port: 8000

$ curl http://localhost:9000/add\?a\=1\&b\=100
Result: 101, from port: 8001

$ curl http://localhost:9000/add\?a\=1\&b\=81
Result: 82, from port: 8000

可以看到两个 compute-service 客户端被交替调用。这是 Ribbon 在客户端已经实现了对服务调用的均衡负载。

架构

  • 一个服务注册中心 Eureka Server 端口为7000
  • Client 跑了两个实例,端口分别为 8000、8001 分别向服务注册中心注册
  • Consumer 端口为9000,向服务注册中心注册
  • 当 Consumer 通过 RestTemplate 调用 Client 的 add 接口时,因为用 Ribbon 进行了负载均衡,会轮流的调用 Client:8000、8001 两个端口的 add 接口

Feign

  • Feign 基于接口的注解请求
  • Feign 整合了 Ribbon

添加新的 Module,命名为 feignConsumer,添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<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-feign</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

因为整合了 Ribbon,所以主程序中只需要注解 @EnableFeignClients 即可:

1
2
3
4
5
6
7
8
9
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}

配置文件 application.properties 和上面的差不多:

1
2
3
4
5
6
7
server.port=9100

spring.application.name=feignConsumer

eureka.client.service-url.defaultZone=http://localhost:7000/eureka/

feign.hystrix.enabled=true

定义消费的接口:

1
2
3
4
5
6
7
// 消费 computeService
@FeignClient(value = "computeService")
public interface FeignComputeService {

@GetMapping("/add")
String add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);
}

控制器:

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class FeignConsumerController {

@Resource
private FeignComputeService computeService;

@GetMapping("/add")
public String add(@RequestParam Integer a, @RequestParam Integer b) {
return computeService.add(a, b);
}
}

同样,像上面那样启动多个客户端后进行测试。

Feign

1
2
3
4
5
6
7
8
9
10
11
$ curl http://localhost:9100/add\?a\=1\&b\=66
Result: 67, from port: 8001

$ curl http://localhost:9100/add\?a\=1\&b\=45
Result: 46, from port: 8000

$ curl http://localhost:9100/add\?a\=1\&b\=100
Result: 101, from port: 8001

$ curl http://localhost:9100/add\?a\=1\&b\=81
Result: 82, from port: 8000

结果和 Ribbon 一样,对服务提供方 client 实现了负载均衡。

参考:spring-cloud-feign

Author

Zoctan

Posted on

2018-05-26

Updated on

2023-03-14

Licensed under