SpringCloud下基于ZooKeeper的服務(wù)注冊(cè)與發(fā)現(xiàn)實(shí)踐
ZooKeeper作為分布式協(xié)調(diào)組件,也可以作為SpringCloud下的注冊(cè)中心進(jìn)行使用

通過Docker先建立一個(gè)ZooKeeper服務(wù)
#?拉取鏡像
docker?pull?zookeeper
#?創(chuàng)建?ZooKeeper?容器
docker?run?-p?2181:2181?-d?\
???--name?ZooKeeper-Service?\
???zookeeper
進(jìn)入ZooKeeper容器,在/conf/zoo.cfg文件中添加下述內(nèi)容,以開啟四字命令。然后重啟ZooKeeper容器
# 開啟四字命令
4lw.commands.whitelist=*
如下所示

現(xiàn)在,通過ZooKeeper客戶端PrettyZoo執(zhí)行四字命令envi來進(jìn)一步明確ZooKeeper版本信息——其版本為3.6.2,如下所示

POM依賴
這里我們建立一個(gè)SpringBoot項(xiàng)目——payment,作為服務(wù)的提供者。對(duì)于ZooKeeper作為注冊(cè)中心的場(chǎng)景,在SpringCloud直接使用spring-cloud-starter-zookeeper-discovery依賴即可。需要注意的是:
- Zookeeper依賴的版本需與我們的所使用服務(wù)端版本保持一致, 故需從spring-cloud-starter-zookeeper-discovery排除該依賴,并顯式引入3.6.2版本的Zookeeper依賴
- Zookeeper日志依賴與SpringBoot日志依賴沖突, 故需這里排除前者的日志依賴
<dependencyManagement>
??<dependencies>
????
????<dependency>
??????<groupId>org.springframework.bootgroupId>
??????<artifactId>spring-boot-dependenciesartifactId>
??????<version>2.2.2.RELEASEversion>
??????<type>pomtype>
??????<scope>importscope>
????dependency>
????
????<dependency>
??????<groupId>org.springframework.cloudgroupId>
??????<artifactId>spring-cloud-dependenciesartifactId>
??????<version>Hoxton.SR1version>
??????<type>pomtype>
??????<scope>importscope>
????dependency>
??dependencies>
dependencyManagement>
<dependencies>
??
??<dependency>
????<groupId>org.springframework.cloudgroupId>
????<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
????<exclusions>
??????
??????<exclusion>
????????<groupId>org.apache.zookeepergroupId>
????????<artifactId>zookeeperartifactId>
??????exclusion>
????exclusions>
??dependency>
??<dependency>
????<groupId>org.apache.zookeepergroupId>
????<artifactId>zookeeperartifactId>
????<version>3.6.2version>
????<exclusions>
??????
??????<exclusion>
????????<groupId>org.slf4jgroupId>
????????<artifactId>slf4j-log4j12artifactId>
??????exclusion>
????exclusions>
??dependency>
dependencies>
配置文件
配置文件中只需通過spring.cloud.zookeeper.connect-string配置項(xiàng)指定ZooKeeper服務(wù)地址信息即可
#?通用配置
spring:
????application:
????????name:?payment
????profiles:
????????active:?payment3
---
#?payment服務(wù)實(shí)例3配置
spring:
????profiles:?payment3
????cloud:
????????zookeeper:
????????????#?ZooKeeper?地址信息
????????????connect-string:?127.0.0.1:2181
server:
????port:?8003
Java實(shí)現(xiàn)
簡(jiǎn)便起見,這里我們直接提供了一個(gè)Controller,用于測(cè)試
@RestController
@RequestMapping("pay")
public?class?PaymentController?{
????@Value("${server.port}")
????private?String?serverPort;???
????@GetMapping("/hello")
????public?String?hello(@RequestParam?String?name)?{
????????String?msg?=?"[Payment?Service-"+?serverPort?+"]:?"?+?name;
????????return?msg;
????}
}
然后在啟動(dòng)類上添加 @EnableDiscoveryClient 注解即可
import?org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public?class?PaymentApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(PaymentApplication.class,?args);
????}
}
搭建服務(wù)消費(fèi)者配置文件
類似地,我們還建立一個(gè)SpringBoot項(xiàng)目——order,作為服務(wù)消費(fèi)者。由于其POM依賴與服務(wù)提供者的POM依賴并無二致。故這里不再贅述,直接復(fù)制即可。配置文件同理,如下所示
spring:
????application:
????????name:?order
????profiles:
????????active:?order2
---
#?order服務(wù)實(shí)例2配置
spring:
????profiles:?order2
????cloud:
????????zookeeper:
????????????#?ZooKeeper?地址信息
????????????connect-string:?127.0.0.1:2181
server:
????port:?81
Java實(shí)現(xiàn)
首先聲明創(chuàng)建RestTemplate實(shí)例。一個(gè)是普通的RestTemplate實(shí)例,一個(gè)則是添加了 @LoadBalanced 注解的RestTemplate實(shí)例。前者可進(jìn)行基于IP、Port服務(wù)調(diào)用;后者由于添加了 @LoadBalanced 注解,其一方面可進(jìn)行基于服務(wù)名的服務(wù)調(diào)用,另一方面支持負(fù)載均衡
@Configuration
public?class?RestTemplateConfig?{
????/**
?????*?普通的restTemplate實(shí)例,?可利用IP、Port調(diào)用服務(wù)
?????*?@return
?????*/
????@Bean
????public?RestTemplate?restTemplate1()?{
????????return?new?RestTemplate();
????}
????/**
?????*?@LoadBalanced?注解作用:
?????*???1.?基于服務(wù)名調(diào)用的restTemplate實(shí)例
?????*???2.?支持負(fù)載均衡
?????*?@return
?????*/
????@Bean
????@LoadBalanced
????public?RestTemplate?restTemplate2()?{
????????return?new?RestTemplate();
????}
}
然后通過Controller調(diào)用Payment服務(wù)接口。下面展現(xiàn)了 傳統(tǒng)地基于IP、Port信息 和 基于服務(wù)名 兩種形式的服務(wù)調(diào)用
@RestController
@RequestMapping("order")
public?class?OrderController?{
????//?使用?固定IP、Port
????public?static?final?String?PAYMENT_URL_1?=?"http://localhost:8003";
????//?使用?注冊(cè)中心的服務(wù)名
????public?static?final?String?PAYMENT_URL_2?=?"http://payment";
????@Qualifier("restTemplate1")
????@Autowired
????private?RestTemplate?restTemplate1;
????@Qualifier("restTemplate2")
????@Autowired
????private?RestTemplate?restTemplate2;
????@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;
????}
}
最后,在啟動(dòng)類上添加 @EnableDiscoveryClient 注解
import?org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public?class?OrderApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(OrderApplication.class,?args);
????}
}
測(cè)試啟動(dòng)payment、order服務(wù),通過ZooKeeper客戶端PrettyZoo可以看出均注冊(cè)成功

然后通過curl驗(yàn)證測(cè)試,服務(wù)調(diào)用正常符合預(yù)期,如下所示

- Spring微服務(wù)實(shí)戰(zhàn) John Carnell著
