【ZooKeeper】Spring Boot 整合 ZooKeeper

ZooKeeper是一个分布式协调工具,可以实现注册中心功能,Spring Cloud中整合ZooKeeper时创建的服务节点是临时节点。ZooKeeper详细介绍参考文章 【ZooKeeper】ZooKeeper

本文将给出 Spring Boot 整合 ZooKeeper 的案例。

支付服务

新建名为cloud-provider-payment8004的支付服务Maven工程,占用端口8004。

引入 Maven 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Spring Cloud整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3 防止与3.4.9起冲突-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>

需要注意,spring-cloud-starter-zookeeper-discovery场景启动器自带一个ZooKeeper依赖,其版本可能与自己的ZooKeeper版本不兼容,从而无法启动Spring Boot项目,因此在pom文件中首先排除掉spring-cloud-starter-zookeeper-discovery中的ZooKeeper依赖,再自己添加符合自己版本的ZooKeeper依赖。(也可能会出现log4j依赖的冲突,解决方案相同)

修改配置文件

1
2
3
4
5
6
7
8
9
10
11
# 8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8004

# 服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # 192.168.111.144:2181 #

创建主启动类

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient // 该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class, args);
}
}

创建 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@Slf4j
public class PaymentController
{
@Value("${server.port}")
private String serverPort;

@RequestMapping(value = "/payment/zk")
public String paymentzk()
{
return "springcloud with zookeeper: " + serverPort + "\t" + UUID.randomUUID().toString();
}
}

测试

启动支付服务8004注册进ZooKeeper(要先启动zookeeper的server)

1
2
3
4
5
6
7
8
9
10
11
[zk: localhost:2181(CONNECTED) 0] ls /
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /services/cloud-provider-payment
[a4567f50-6ad9-47a3-9fbb-7391f41a9f3d]
[zk: localhost:2181(CONNECTED) 2] get /services/cloud-provider-payment/a4567f50-6ad9-47a3-9fbb-7391f41a9f3d
{"name":"cloud-provider-payment","id":"a4567f50-6ad9-47a3-9fbb-7391f41a9f3d","address":"192.168.199.218","port":8004,"ss
lPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","
name":"cloud-provider-payment","metadata":{}},"registrationTimeUTC":1612811116918,"serviceType":"DYNAMIC","uriSpec":{"pa
rts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":"
:","variable":false},{"value":"port","variable":true}]}}
[zk: localhost:2181(CONNECTED) 3]

json格式化get /services/cloud-provider-payment/a4567f50-6ad9-47a3-9fbb-7391f41a9f3d的结果:

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
{
"name": "cloud-provider-payment",
"id": "a4567f50-6ad9-47a3-9fbb-7391f41a9f3d",
"address": "192.168.199.218",
"port": 8004,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "cloud-provider-payment",
"metadata": { }
},
"registrationTimeUTC": 1612811116918,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [
{
"value": "scheme",
"variable": true
},
{
"value": "://",
"variable": false
},
{
"value": "address",
"variable": true
},
{
"value": ":",
"variable": false
},
{
"value": "port",
"variable": true
}
]
}
}

订单服务

新建名为cloud-consumerzk-order80的订单服务Maven工程,端口号为80。

引入 Maven 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Spring Cloud整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3 防止与3.4.9起冲突-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>

需要注意,spring-cloud-starter-zookeeper-discovery场景启动器自带一个ZooKeeper依赖,其版本可能与自己的ZooKeeper版本不兼容,从而无法启动Spring Boot项目,因此在pom文件中首先排除掉spring-cloud-starter-zookeeper-discovery中的ZooKeeper依赖,再自己添加符合自己版本的ZooKeeper依赖。(也可能会出现log4j依赖的冲突,解决方案相同)

修改配置文件

1
2
3
4
5
6
7
8
9
10
server:
port: 80

# 服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-consumer-order
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # 192.168.111.144:2181 #

创建主启动类

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class OrderZKMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZKMain80.class, args);
}
}

业务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced // 负载均衡
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderZKController
{
public static final String INVOKE_URL = "http://cloud-provider-payment";

@Resource
private RestTemplate restTemplate;

@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
return result;
}
}

测试

先后运行ZooKeeper服务端,cloud-consumerzk-order80cloud-provider-payment8004

打开ZooKeeper客户端:

1
2
3
4
5
[zk: localhost:2181(CONNECTED) 0] ls /
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /services
[cloud-consumer-order, cloud-provider-payment]
[zk: localhost:2181(CONNECTED) 2]

访问测试地址:http://localhost/consumer/payment/zk

原理

80客户端将从ZooKeeper中订阅8004服务端的URL信息,从而利用RestTemplate对象调用该URL对应的Rest请求,从而实现远程调用的效果